AndroidPatch方案与持续交付方案与持续交付
Android 不仅系统版本众多,机型众多,而且各个市场都各有各的政策和审核速度,每次发布一个版本对于开发同学来
讲都是一种漫长的煎熬。相比于 iOS 两三天就能达到 80% 的覆盖速度而言,Android 应用版本升级至少需要两周才能
达到 80% 的升级率,严重阻碍了版本迭代速度。也导致市场上 App 版本分散,处理 bug 和投诉等也越来越麻烦。
修复的 bug 需要等待下个版本发布窗口才能发布?
已经 ready 的需求排队上线,需要等待其他 Feature Team 合入代码?
老版本升级速度慢?频繁上线版本提醒用户升级,影响用户体验?
这几个问题是每个 App 开发同学都必然要面对的。那么有没有方法能在用户无感知的情况下加速 bug 处理和版本迭代
速度?
在这方面 PC 端 Chrome 浏览器的 patch 升级方案给我们了一个很好的借鉴:当 Chrome 有版本升级的时候会自动下
载 patch 文件。下次启动后,Chrome 就已经是新版本。
他山之石,可以攻玉
近一两年 Android 热补丁框架非常热门。从最初 360 动态下发 lua 脚本,到后来出现的各种方案,如雨后春笋般出
现。早期的补丁框架偏向于以代码修复为主,主要分为两大类:native hook 方案和 Multidex 方案。
native hook 方案如阿里巴巴的 AndFix 和 Dexposed。Multidex 方案如 Qzone。切入点都是替换掉将要执行的代码。
基于 Qzone 方案的思路,出现了 nuwa 这个比较完善的库,工具链比较完善。
类似 Chrome 的 patch 升级方案足以满足加速 bug 处理和版本迭代速度的需求,给了我们很大的借鉴意义。在安卓系
统上,可以通过 hotfix 的思路来达到这一目的:下发补丁文件,更新 App 版本。
站在巨人的肩膀上
在今年 3 月份开始做技术选型的时候把上面的几种方案试了一轮。其中 AndFix 甚至跟上了现网的一个发布版本,但是
由于影响正向开发过程(只能修改方法、不能修改 field、不能新增类等问题)、库本身难于维护(需要依赖外部开源
力量进行维护)以及发现的莫名其妙的 bug(导致我们 App 下发 patch 后白屏),所以即使跟上了发布版本也没有使
用。nuwa 仅支持更新 Java 代码,不能更新资源和 so 文件,满足不了我们的需求。
没有好用的轮子,我们决定自己造一个,于是有了现在的 patch 方案。
App 只是一个加载器
既然做安卓 patch 方案,最好的结果就是能支持更新 App 所有的代码和资源。但是
Application 类是 App 启动之初就被安卓系统加载起来,所以至少 Application 类和它启动依赖的其他业务类是不能被
更新的?
修复 bug 或者版本迭代过程中难免会遇到需要修改资源文件的情况。资源文件能更新吗?
native 实现的 so 文件如何更新?
针对上面三个问题, 我们的设计是把 App 仅仅当做一个加载器。系统启动 App 之后,加载器决定将要运行的代码和
资源的位置。当有新功能或者 bugfix 需要推送给用户,替换加载器内容即可。
支持更新全部代码
上面提到 Application 由于启动就被加载而不能被更新的问题,我们代理了真实 Application 类的创建过程。通过代理
Application,控制 Application 从新 dex 文件中加载。假设真实的 Application 类是 MyApplication。我们在编译期间自
动修改 AndroidManifest.xml 文件,把 MyApplication 替换为 MoaiApplication(是 App 的入口 Application)。App 启
动后由 MoaiApplication 加载完相应的文件(dex/资源文件/so 文件)后,再将控制权交回给 MyApplication。
代理生命周期
将控制权交回给 MyApplication,我们最初是代理 MyApplication 的生命周期。具体做法是,MoaiApplication 决定加载