您的位置:首页 > 移动开发 > Android开发

Android 热修复技术浅析

2017-01-30 11:47 288 查看
转载请注明本文出自 clevergump 的博客:http://blog.csdn.net/clevergump/article/details/54782635, 谢谢!

一. 热修复技术简介

什么是热修复技术?

通过向用户下发补丁包的方式, 让应用能够在无需重新安装的情况自动集成补丁包, 实现更新的技术.



二. 热修复技术的优缺点

优点:

无需重新发布到应用市场, 节省了从提交应用市场审核到审核通过的时间.

用户无需重新安装,只要上线就能无感知地更新.

缺点:

补丁只能针对单一客户端版本,随着版本差异变大补丁体积也会增大.

补丁不能支持所有的修改,例如AndroidManifest.

补丁无论对代码还是资源的更新成功率都无法达到100%.

结论:

热修复技术只适用于特定场景,无法完全代替传统的升级方式.

三. 热修复技术的适用场景

1. 轻量而快速的升级

适用于修改量较少, 补丁包较小的情况。在补丁包极小的情况下,也可以直接使用移动网络下载更新, 这样能达到快速升级、快速验证、缩短发布流程的目的. 注意:是否需要使用用户流量,需要慎重考虑。例如: 下图是微信某次升级试验中, 两种升级方式的对比:



2. 静默远程bug调试和验证



3. 数据统计

如果想对同一批用户做两种测试, 传统方式无法让这批用户去安装两个版本。使用热修复技术,就可以方便地对同一批用户不停地更换补丁, 然后得出不同的测试结果, 进行数据统计和对比分析. 例如: 如果想探究某次技术升级后的用户满意度或bug出现率, 就可以使用AB测试, 只给一部分用户推送升级补丁, 其他用户则依然保持原先的版本, 通过对比这两类用户各自的使用状况, 从而就可以知道这次热修复的内容是否需要继续完善或改进等. 如果发现使用了补丁包的用户的满意度提高了, 或者出现bug的概率降低了, 那么就可以将本次热修复的补丁包下发给所有用户了.



4. 其他

例如: Android Studio 的 Instant Run (热部署) 技术等.

四. 当前主流热修复方案简介及对比

1. 微信Tinker方案

开发团队微信
方案简介使用 ClassLoader 动态加载多个dex文件,改变dex文件的加载顺序
优点开发简单透明,成功率较高,支持Java、so、资源文件的替换和新增,补丁包较小,性能损耗较小,支持gradle。
缺点Dalvik机型Rom体积较大,补丁不能即时生效。
是否开源
技术支持情况有官方技术支持QQ群 (群号: 377388954)
GitHub主页https://github.com/Tencent/tinker

2. 腾讯QZone方案

开发团队QQ空间
方案简介使用 ClassLoader 动态加载多个dex文件,改变dex文件的加载顺序.
优点开发简单透明,成功率较高,支持so、资源文件的替换
缺点补丁包较大,性能损耗较大,补丁不能即时生效,不支持新增Java文件.
是否开源
技术支持情况无(因为不开源)
类似开源方案Nuwa, RocooFix

3. 阿里巴巴AndFix方案

开发团队阿里巴巴
方案简介采用native hook,替换class中方法的实现.
优点补丁即时生效,性能损耗较小,Rom体积较小.
缺点开发复杂,native异常排查难度高,稳定性和兼容性不好,成功率不高,不支持新增Java文件,不支持so、资源文件的替换,不支持gradle.
是否开源
技术支持情况不确定是否有专门的技术支持团队
GitHub主页https://github.com/alibaba/AndFix

4. 美团Robust方案

开发团队美团
方案简介使用 ClassLoader 动态加载多个dex文件,改变dex文件的加载顺序,同时又借鉴了multidex的设计.
优点成功率最高,补丁即时生效,性能损耗较小,Rom体积较小.
缺点开发复杂不透明,不支持新增Java文件,不支持so、资源文件的替换,不支持gradle.
是否开源否 (今后有可能开源)
技术支持情况无 (因为暂未开源)

5. 当前主流方案的对比

方案名称TinkerQZoneAndFixRobust
类替换yesyesnono
So替换yesnonono
资源替换yesyesnono
全平台支持yesyesyesyes
即时生效nonoyesyes
性能损耗较小较大较小较小
补丁包大小较小较大一般一般
开发透明yesyesnono
复杂度较低较低复杂复杂
gradle支持yesnonono
Rom体积较大较小较小较小
成功率较高较高一般最高
是否开源
技术支持情况有官方QQ群

五. 当前商用APP推荐使用的热修复方案

通过前边各大方案的对比可知, 微信Tinker方案相对于其他方案具有如下优势:

几乎支持所有文件的替换,包括:Java文件,资源文件,so文件等。

稳定性高。该方案已应用于微信APP中,其稳定性已得到了微信上亿用户的验证。

官方更新维护及时,且代码已开源,代码是在 framework层 (而不是 native层) 进行修改, 这样可以让更多从事 APP开发或 framework开发的同行参与到该方案的维护中,从而促进了该方案的快速完善。

有相关的技术支持QQ群,如有疑问可以直接和开发人员沟通讨论, 便于快速解决技术难题。

所以,对于商用APP,当前推荐使用微信Tinker方案

六. 热修复技术原理分析(开源nuwa方案)

下面以开源框架 nuwa (https://github.com/jasonross/Nuwa) 为例,来介绍基于ClassLoader的相关热修复方案的实现原理。

基于ClassLoader实现热修复,简单来说,就是把多个dex文件塞入到 APP 的 ClassLoader之中. 如果多个dex文件中有重复的类,当用到这个重复的类的时候, 系统内部会按照一定的优先级顺序先后遍历各个dex文件, 只要在某个dex文件中找到了该类, 就会停止后续的遍历, 所以后续其他 dex中具有同名的类就不会被调用了.

假设一个 APP被分成多个dex文件, ClassLoader要从中找出 Bug.class文件进行加载, 而 dex文件的优先级是: classes1.dex > classes2.dex > classes3.dex > … 那么, ClassLoader 查找该 class文件的流程图如下:



所以, 如果一个类存在bug (假设该类名为 Bug.java), 那么修复步骤如下:

修复Bug.java 中的bug代码

将修复了bug后的 Bug.java 文件所编译出的class文件打包成dex文件(假设名为patch.dex)

将patch.dex文件注入到原APP中, 并且需要让该dex被系统的 ClassLoader遍历时的优先级最高, 这样, 原先存在bug的那个Bug.class文件就会因为优先级较低而不会被加载了.

如何让patch.dex的优先级最高呢?

简单来说, 组成一个 APP的所有 dex文件都被存放在一个叫做 dexElements 的数组中, ClassLoader 要遍历查找某个 class文件, 其实就是从 dexElements 数组中按照数组索引从0开始逐渐增大的顺序, 一个一个地取出 dex文件进行查找, 只要找到就立即结束. 数组索引越小的 dex文件, 就越会被 ClassLoader优先遍历. 所以, 要想让一个dex文件被 ClassLoader查找的优先级最高(也即: 被 ClassLoader第一个查找), 只需将该 dex文件放在该数组的索引0位置处即可. 我们可以利用发射技术, 获取到该数组, 然后将补丁文件 patch.dex注入到该数组中的索引0位置即可.

(注意: 以上只是为了便于理解而简化了的描述, 实际情况更复杂, 需要看具体的源码)

patch.dex 注入时的 CLASS_ISPREVERIFIED 问题

在按照上述步骤注入 patch.dex时, 却可能会报如下错误, 为什么?



其实, 虚拟机为了性能考虑, 加载的不是 dex文件, 而是将 dex经过进一步优化后的 odex文件. 虚拟机在生成 odex文件的过程中, 会判断某个类是否引用了其他 dex文件中的代码, 如果没有, 则会为该类打上CLASS_ISPREVERIFIED 标签, 表示此后该类将一直不会引用其他 dex文件中的代码, 这其实是一种优化.

所以, 假设我们原先的 APP中有两个类: Caller类和 Bug类, 二者都在同一个 dex文件中, 并且Caller类中会调用 Bug类的代码, 而没有调用其他 dex文件中的代码, 那么当我们安装该 APP时, Caller类就会被打上CLASS_ISPREVERIFIED 标签. 此后, 我们发现 Bug类的代码存在 bug需要修复, 如果采用热修复技术, 那么就意味着 Caller类需要调用来自 patch.dex中的 Bug类, 也就是需要调用其他 dex文件中的代码, 由于 Bug类先前已被打上 CLASS_ISPREVERIFIED 标签, 所以会报错, 热修复失败. 要想继续使用热修复技术, 就必须阻止 Caller类被打上该标签. 更广泛地说, 要想避免该问题, 就必须要让原先 APP中的所有类都不能打上该标签.

如何让APP中的所有类都不打上 CLASS_ISPREVERIFIED 标签?

其实很简单, 只需在 APP的第一个版本中就内置一个 dex文件, 让 APP中的所有类都去调用该 dex文件中的某个类即可. 这也就是业内俗称的 “插桩”技术.

例如: 可以在 APP的 assets文件夹中内置一个 hack.dex文件, 该hack.dex文件中只包含一个 Hack.class文件. 然后在该 APP的所有类中都调用如下代码:

System.out.println(Hack.class);


七. demo代码下载

NuwaDemo: https://github.com/clevergump/NuwaDemo

八. 参考资料

1. 微信Tinker方案:

微信Android热补丁实践演进之路 https://github.com/WeMobileDev/article/blob/master/%E5%BE%AE%E4%BF%A1Android%E7%83%AD%E8%A1%A5%E4%B8%81%E5%AE%9E%E8%B7%B5%E6%BC%94%E8%BF%9B%E4%B9%8B%E8%B7%AF.md#rd

tinker GitHub: https://github.com/Tencent/tinker

2. QZone方案及类似的开源框架

QQ空间终端开发团队—安卓App热补丁动态修复技术介绍 http://mp.weixin.qq.com/s?__biz=MzI1MTA1MzM2Nw==&mid=400118620&idx=1&sn=b4fdd5055731290eef12ad0d17f39d4a&scene=0#wechat_redirect

Nuwa GitHub: https://github.com/jasonross/Nuwa

HotFix (Deprecated) GitHub: https://github.com/dodola/HotFix

RocooFix GitHub: https://github.com/dodola/RocooFix

3. Alibaba AndFix方案

AndFix GitHub: https://github.com/alibaba/AndFix

4. 美团Robust方案

Android热更新方案Robust https://zhuanlan.zhihu.com/p/22495059#!

5. 其他

Android 热修复,没你想的那么难 http://kymjs.com/code/2016/05/08/01

各大热补丁方案分析和比较

http://blog.zhaiyifan.cn/2015/11/20/HotPatchCompare/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 热修复