我们部门有很多Android的能力SDK,被很多App(约1000个)集成。每次SDK有微调发布新版本后,App集成需要花上1-2个月时间,很多时候SDK团队和App团队双方都很痛苦。16年10月份,Boss叫搞一个Android的热修复功能。神奇的是,居然让我一个从未搞过Android的人来负责(看来我在老板心中 只能充当救火队员)。我在16年12月完成了第一个版本的实现,后面详细针对200多种机型的调试,就交给其他同事去了。 最近看见已在部门几个产品推广该功能了,想想还是记录下当时实现的思路。
当时首先调研了几个公司的App热更新方案(没办法,当时市场上没有针对SDK的热修复,仅找到针对App的)
阿里百川的Andfix
优点是:能针对方法级别的更新,而且是真正的热修复-不需要重启App
缺点是:1)使用了Java的newInstance()去构造对象,所以不支持带参数的构造函数 2)也不支持新增类和类字段 3)因为该方案本持是在native C++层替换函数指针来实现方法的"热替换",牛是很牛了,但据说导致崩机率高。
结论:不适合我司的场景,PASS
备注:在17年1月推出了AndFix的2.0新版本,据说有本质的提高。但因为没有开源,只能围观一下。
QQ的HotFix(开源版本叫Nuwa)
也就是大家熟知的Classloader方案。重启App后更新
优点是:该方案提稳定性是最好的,补丁生效率是最高的。但是对补丁大小有严格限制。
缺点是:开源的Nuwa程序,实际使用后程序不是很稳定,在部分机型上老是崩溃。一旦补丁升级过多,会导致App在运行时效率低下。
微信的Tinker
整个更新过程和QQ的方案类似,但本质却完全不同。Tinker在客户端在收到补丁后,将用原Apk文件+补丁做一次合成,形成新的APK文件,再基于新的APK文件运行程序
优点是:不受限补丁更新次数,不受限于热修复本身,一旦程序启动后,对性能无影响。
缺点是:启动程序(比如微信)时,因为有合成动作,占用内存较多。
美团的热修复
在所有Class的所有Method中自动插桩一段代码。这段代码包含了更新的逻辑
优点是:是基于Java的原理实现,而非Android本身原理,原理更加通用和简单。
缺点是:增加APK包体大小,直接导致部分DEX文件超过65535 Method总数的限制。尽管后续做了优化,但个人感觉太过简单粗暴。
结论:PASS掉
携程的插件化方案
把每个SDK做成APK格式,由主程序加载所有APK文件。
优点是:很符合我司SDK更新的场景,而且能同时更新SDK的UI、Java代码、so库。看起来很完美。
缺点是:老板说,SDK热修复方案要对App层无感知。但携程的插件化方案需要对App框架进行改造。1000个App,得改到啥时候啊。
结论:最开始本来想采用这套方案来着,后面也只有挥泪PASS掉。
我司其它团队的土方法:
- 去掉SDK的UI层,直接将SDK的界面通过纯Java代码实现,界面中涉及的图片,通过网络在线加载
- 把Java层切成两部分:接口和核心逻辑,分别单独打包。接口层初始化时负责加载核心层的Java包。
最后基于种种考虑,采用了QQ和微信的混合方案, 客户端热修复的底层实现,使用Nuwa中代码(加载dex包部分);补丁的生成方案使用微信的dexDiff算法。
缺点就是:不能更新SDK的UI层,仅支持更新SDK的Java层和so库。 主要原因是SDK本身的限制,毕竟不是App,拿不到相应的系统权限。
大体方案如下图所示:
本次介绍就到这里。抽空再介绍一下实际操作中,遇到热修复不生效和崩机时的回退方案。