总览
| Tinker | QZone | AndFix | Robust | |
|---|---|---|---|---|
| 类替换 | yes | yes | no | no |
| So替换 | yes | no | no | no |
| 资源替换 | yes | yes | no | no |
| 全平台支持 | yes | yes | yes | yes |
| 即时生效 | no | no | yes | yes |
| 性能损耗 | 较小 | 较大 | 较小 | 较小 |
| 补丁包大小 | 较小 | 较大 | 一般 | 一般 |
| 开发透明 | yes | yes | no | no |
| 复杂度 | 较低 | 较低 | 复杂 | 复杂 |
| gradle 支持 | yes | no | no | no |
| Rom 体积 | 较大 | 较小 | 较小 | 较小 |
| 成功率 | 较高 | 较高 | 一般 | 最高 |
Tinker
关键词
- 重启生效、反射、类加载、DexDiff
简介
- tencent 的热修复开源框架。
原理
- Tinker 通过计算对比指定的 Base Apk 中的 dex 与修改后的 Apk 中的 dex 的区别,补丁包中的内容即为两者差分的描述。运行时将 Base Apk 中的 dex 与补丁包进行合成,重启后加载全新的合成后的 dex 文件。该框架使用了腾讯的差分算法:DexDiff 算法,比较新的 dex 文件和旧的 dex 文件生成差分信息,将该差分信息发送给客户端,客户端根据该差分信息和原有的 dex 文件生成目标 dex 文件。对于非 dex 的替换,Tinker 仍然使用 bsdiff 差分算法(bsdiff 差分算法是全格式支持的,因为它比较的是字节码)。Tinker 之所以使用新的差分算法,因为 DexDiff 对于 dex 文件的差分比较具有更高的比较效率和合成效率。

使用
AndFix
关键词
- 即时生效、注解、NDK
简介
- alibaba 的热修复开源框架。
原理
- 在 native 动态替换 Java 层的方法,通过 native 层 hook Java 层的代码。Java 层所有的 Method 在 native 层都有一个 ARTMethod 指针指向 Java 层的方法,AndFix 通过替换 ARTMethod 的指向,来实现对含有 bug 方法的替换,所以 AndFix 的替换粒度是方法。

使用
- 使用 AndFix 提供的 @MethodReplace() 注解。
@MethodReplace(clazz="com.demo.DemoClassName", method="method_ToBeReplaced")
public void method_ToReplace(){
// ...
}
Robust
Android 平台出现了一些优秀的热更新方案,主要可以分为两类:一类是基于 multidex 的热更新框架,包括 Nuwa、Tinker 等;另一类就是 native hook 方案,如阿里开源的 Andfix 和 Dexposed。这样客户端也有了实时修复线上问题的可能。但经过调研之后,我们发现上述方案或多或少都有一些问题,基于native hook 的方案:需要针对 dalvik 虚拟机和 art 虚拟机做适配,需要考虑指令集的兼容问题,需要 native 代码支持,兼容性上会有一定的影响;基于 Multidex 的方案,需要反射更改 DexElements ,改变 Dex 的加载顺序,这使得 patch 需要在下次启动时才能生效,实时性就受到了影响,同时这种方案在 android N [speed-profile] 编译模式下可能会有问题,可以参考 Android N 混合编译与对热补丁影响解析。考虑到美团 Android 用户机型分布的碎片化,很难有一个方案能覆盖所有机型。 去年底的 Android Dev Summit 上, Google 高调发布了 Android Studio 2.0 ,其中最重要的新特性 Instant Run ,实现了对代码修改的实时生效(热插拔)。我们在了解 Instant Run 原理之后,实现了一个兼容性更强的热更新方案,这就是产品化的 hotpatch 框架-- Robust 。
关键词
- 即时生效、注解、插桩、代理
简介
- 美团的开源热修复框架。
原理
- Robust 插件对每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码,插入过程对业务开发是完全透明。详细代码见引用的美团技术文章。Robust 的替换粒度是方法。同时,因为源代码中被插入了新的 if 判断语句,属于字节码插桩技术。
如 State.java 的 getIndex 函数:
public long getIndex() {
return 100L;
}
被处理成如下的实现:
public static ChangeQuickRedirect changeQuickRedirect;
public long getIndex() {
if(changeQuickRedirect != null) {
//去执行补丁的 getIndex() 方法,并返回。
}
return 100L;
}
使用
-
1.集成了 Robust 后,生成 apk。保存期间的混淆文件 mapping.txt,以及 Robust 生成记录文件 methodMap.robust ; 2.使用注解 @Modify 或者方法 RobustModify.modify() 标注需要修复的方法 ; 3.开启补丁插件,执行生成 apk 命令,获得补丁包 patch.jar ; 4.通过推送或者接口的形式,通知 app 有补丁,需要修复; 5.加载补丁文件不需要重新启动应用。
QZone
详解请转到我的另一篇文章 基于QZone dex分包技术的热修复插件详解
关键词
- 重启生效、反射、类加载
简介
- QQ空间基于的是 dex 分包方案。把 Bug 方法修复以后,放到一个单独的 dex 补丁文件,让程序运行期间加载 dex 补丁,执行修复后的方法。
原理
- 如何做到简介中的描述?在 Android 中所有我们运行期间需要的类都是由 ClassLoader (类加载器)进行加载。因此让 ClassLoader 加载全新的类替换掉出现 Bug 的类即可完成热修复。
