全网独家盘点 Android 热修复方案(含阿里巴巴、美团、腾讯等
腾讯 QZone Muitidex 方案
=====================================================================
热修复方案按照是否必须重启 分为两类:?重启生效 / 即时生效。按照 实现方式可以分为 3 类:?java 层的实现 / native 层的实现 / java native 混合实现
AndFix 是?无需重启?的?native 层?的实现. 但是,AndFix 目前已经 3 年多没维护更新。因为阿里已经有了新的替代方案,不再需要维护。另外,这种纯 native 的实现方式,兼容性十分堪忧。既然已经被弃用,但是稍微了解一下 实现方案也是没问题的。
上图解读:图中有一段程序按照?
A=>B=>C
的顺序去执行,然而发现执行到 B 的时候,存在一个 bug,AndFix 的修复方式为:在 native 层执行到 B 方法的时候,把方法的指针指向了?补丁包里的 B 方法,绕过了原来的 B 方法。从而达到了修复 bug 的目的。
使用方法:
在需要修复的方法上面,加上 @MethodReplace 注解,给定参数,class 和 method,表示 该方法替换为 哪个类的哪个方法。
缺陷:修复粒度为:method. AndFix 只能以方法为粒度去修复 bug。作用有限,针对大范围的类替换和资源替换,那就无能为力了。
Robust 是?即时生效的 Java 层实现的热修复实现方案.
美团的 Robust 方案,是参考了谷歌的 InstantRun 方案(之前在 androidStudio 里面有这个选项,可以选择打开 instant run 运行 app)的思路而设计出来的。
其主要设计思想就是一句话:编译打包时,在程序的某些方法里面,都插入一段代码(全自动操作):
当?
changeQuickRedirect
不为空的时候,该方法就会命中?if(changeQuickRedirect!=null)
,从而执行修复的实现代码。当为空的时候,则正常执行原逻辑。
而平时我们自己编码,只需要加上一个?
@modify
注解,来标记这个方法需要打补丁包,也就是需要插入上面这个?if(changeQuickRedirect!=null)
代码段。?
为什么它可以即时生效?
上图解析:利用 ClassLoader,当客户端手机收到补丁包 patch.dex 的时候,执行补丁包,把指定方法的?
changeQuickRedirect
用反射的手段赋值,让它变成非空。从而让下一次程序逻辑走到这里的时候,走修复之后的逻辑。
Robust 是如何将这么多?****if(changeQuickRedirect!=null)
代码段插入到代码逻辑中的?:
上图中的?
if(changeQuickRedirect!=null)
代码段,并非我们手动编写,而是由 Robust 框架自动插入的。这个技术叫做?字节码插桩,意为:对 class 进行操作,
按照 class 文件的格式,插入自己想要的逻辑。目前 Robust 支持两种字节码插桩方案?AspectJ
?和?Javasist
.
腾讯 Tinker dexdiff / DexMerge 方案
Tinker 是腾讯自研的?重启生效的?Java 层的实现.
原理
Tinker 基于一个基准 dex,以及修复 bug 之后的 dex,使用 dexdiff 算法,计算出差分包 dex。然后把差分包推送给客户端,客户端收到之后,重启运行 app,把差分包 dex 和原 dex 进行合并,形成新的 dex。然后 ClassLoader 去创建类 class 对象的时候,就会创建修复 bug 之后的类 class 对象。从而达到 修复 bug 的目的。?
Dexdiff 算法
了解增量更新的人应该知道 bsdiff。bsdiff 是无视文件格式,生成两个二进制文件的差异文件。dexdiff 是基于 bsdiff,并且进行了针对 dex 文件格式的优化。Tinker 除了支持 Dex 修复之外,还支持 so 修复,只不过 so 的差分包,是直接使用的 bsdiff 算法生成的。
Multidex 方案是 基于 ClassLoader 的?纯 java 实现?的?重启生效的热修复方案.
原理
Apk 打包的时候可能生成多个 classes.dex 文件。JVM 中 类加载器 ClassLoader,在程序运行使用到某一个 Class 的时候,是按照顺序查找的方式进行的。一旦找到,就会缓存起来,下一次 loadClass 就不会去查找,而是直接使用缓存中的(所以 Muitldex 方案必须重启 app). 而,当我们把补丁 dex 文件放到 顺序查找的最前面,那么类加载器 查找到它之后,就会直接使用。原来的同样的类便处于后方,不会再生效。由此,使用补丁 Class 完全替换了 原 class.
至于更深入的原理,上一篇?Android Muitldex热更新修复方案原理已经给出了详细讲解。在此就不赘述。
评论