整体架构
1、核心原理
热更新技术在编译期的应用,后期引用到了线上做热更新
2、稳定性
完善的基线对齐、进程级别异常隔离
3、性能
借鉴Buck多任务并发思想,端口扫描、代码扫描、并发编译、并发dx、并发merge dex,在多核机器上加速明显
在class、dex、resource方面做了缓存
优化buck加速dx、DexMerger、资源编译方面,深入改造AAPT流程
4、具有能力
多任务并发,多级缓存,增量范围最小化,懒加载,基于长链接无安装式运行期动态替换,基线对齐触发机制,可调试
传统打包流程
image.pngAAPT会执行2次
第一次生成R.java,进行javac编译
第二次对res里的资源进行编译
最后APKBuilder把编译好的资源、DEX文件打包成APK,签名,安装
整个流程没有缓存,没有多任务处理,没有增量
LayoutCast
通过AS插件、Python脚本,把diff进行编译和打包,生成classes.dex和res.zip,通过adb发送这2个文件,再进行替换
有不足的地方:
- 传统流水式构建,不支持多任务,不能很好地利用该多核优势
- res变化后,LayoutCast的行为与instant-run一致,重新打资源包,然后推送至手机,若资源包过大,TCP传输速度会很慢
- 通过运行时反射R class field来生成ids.xml、public.xml,用于保证增量包res id和全量包res id一致。因为R的id太多,反射耗时太久
- 某些情况下AAPT构建时可能发生数组越界,运行时
- 没有缓存机制
- 代码增量插入在系统dexlist最前端位置,4.x上手机校验不通过
Buck
以工程为单位拆分出多个任务,并发执行,梳理好节点的依赖关系,输出有向拓扑图
建立了细化的缓存系统
增量构建的原理在于,以工程目录为单位构建,发生变更的时候,重新走一次合并各工程dex,对齐,签名
侵入性较强
在FaceBook内部、微信都是用Buck作为默认的构建方案
(拓扑+多任务并发,是非常重要的思想,我的前同事基于此思想开发出了启动优化框架)
整体任务
image.png分为如下几块
- 电脑手机建立长连接
- 扫描各个子工程文件变化
- 各个子工程增量dex构建
- 增量资源包构建
- 合并所有工程dex
- 传输增量包
默认8线程并发
单工程任务
image.png首先扫描文件变化
然后根据扫描结果,考虑运行inc-code-task、inc-res-task
inc-code-task
- check-r-change:检验R文件MD5是否变化,若有变化,把新的R.java加入变更列表
- begin-code-transaction:备份工作空间,在后续步骤出错时,进行回滚
- javac:把扫描出来的Java变更部分,编译
- buck-dx:.class打包成.dex。该工具比Android原生快40%左右
- buck-smart-dex:减小dex体积
inc-res-task
- begin-res-transaction:备份
- merge xml:对同名xml节点合并
- merge ids:若gen-r阶段发现R文件变更,或者更改文件集合里有ids.xml或者public.xml,则对于新老的这些文件,进行merge
- gen ids:通过最后一次生成的资源包,反向生成ids.xml和public.xml,该两个文件在构建增量资源包时候参与编译,可以使得 最后构建出来的资源包的内对于的资源ID与前一次构建的资源包保持一致
- build-inc-res:构建增量包
多级缓存
对class、dex做缓存,这个过程并不复杂,做个缓存而已
对于res,增量包构建后,会和手机端的资源文件做一次sync
在做完缓存与拓扑多任务后,性能已经很卓越了
代码增量
通过植入Dex到DexList,这是经典的热修复原理
对于类的查找,会从DexList的开始进行查找,找到后就不会再往下找了,基于此实现动态替换dex
资源增量
兼容增量包res id、基线包res id
采用上一次生成的public.xml、id.xml参与后续编译
- 运行期反射R class field的放啊不可靠,资源太多,耗时太久
- ApkTool反编译资源包,把所有资源逆向导出
- 对R.java,通过id-gen-tool工具,反向导出id.xml、public.xml,并且会过滤掉枚举常量,解决内存越界问题
高效构建diff res包
根据生成的id.xml、public.xml,放进values中,参与编译后,可以生成正确的resoucres.arsc,不需要编译layout资源和AndroidManifest.xml
并且做了缓存
打包时仅对修改的文件编译后的资源进行打包
最终构建出来diff res包、resoucres.arsc、AndroidManifest.xml
增量包在手机生效
res支持以目录形式存在,所以:
1、解压基线包apk
2、修改AssetsManager对应的path
3、进行sync
4、清空Resources的cache,重新构建Resources
绕过CLASS_ISPREVERIFIED限制
安装包安装的时候,dexopt会扫描dex内的class,class文件内所有直接引用到的类
如果和该class在同一个dex中,会被打上CLASS_ISPREVERIFIED标签
被打上这个标记的类,DVM在运行时检查,若发现引用的类和打标记的类不在同一个dex,会报错
所以只需要对每个class通过ASM引用一个外部dex类即可
后记
有什么写得错误、让人费解或遗漏的地方,希望可以不吝赐教,我会马上更改
学习自
https://yq.aliyun.com/articles/59122?spm=a2c4e.11153940.0.0.351439d5GMvMx1&type=2
网友评论