写在开头
本文主要是跟着官方文档以自己的理解,捋一遍 Amigo 的流程。
在 GitHub 上 Amigo 的 Wiki 中,How it works 分为三个大的步骤:
- 检查补丁包
- 释放 Apk
- 释放 Dex 到指定目录
- 拷贝 So 文件到 Amigo 的指定目录
- 优化 Dex 文件
- 替换修复
- 替换 ClassLoader
- 替换 Dex
- 替换动态链接库
- 替换资源文件
- 替换原有 Application
- Amigo 插件
官方文档讲解的都是精华部分、核心部分。
而这里我们按照 Amigo 一次成功修复的流程来学习它。
怎么实现的
通过学习源码发现,替换用户的 Application 是 Amigo 的第一步,因为它在编译的时候就完成了替换工作。
在 buildSrc/src/main/groovy/me.ele.amigo/AmigoPlugin.groovy 脚本文件中完成了替换原有 Application 的工作。
1. 编译时替换 Application
me.ele.amigo.AmigoPlugin.groovy
manifestFile = output.processManifest.manifestOutputFile
//fake original application as an activity, so it will be in main dex
Node node = (new XmlParser()).parse(manifestFile)
Node appNode = null
for (Node n : node.children()) {
if (n.name().equals("application")) {
appNode = n;
break
}
}
QName nameAttr = new QName("http://schemas.android.com/apk/res/android", 'name', 'android');
applicationName = appNode.attribute(nameAttr)
if (applicationName == null || applicationName.isEmpty()) {
applicationName = "android.app.Application"
}
// 将原来的 Application 替换成 Amigo
appNode.attributes().put(nameAttr, "me.ele.amigo.Amigo")
// new 一个 Node,将原来的 Application 设置为 Activity,以保证其一定会在主 dex 中。
Node hackAppNode = new Node(appNode, "activity")
hackAppNode.attributes().put("android:name", applicationName)
manifestFile.bytes = XmlUtil.serialize(node).getBytes("UTF-8")
而Amigo 框架最核心的代码都在 Amigo.java 中,我们接下来看看 Amigo.java 中都做了哪些事情。
2. 核心类 Amigo.java
核心方法 attachBaseContext() --> attachApplication()
public void attachApplication() {
try {
String workingChecksum = PatchInfoUtil.getWor