专栏名称: 复利大王
分享和推送Java/Android方向的技术和文章,让你成为这方面的大牛,让你每天都成长一点。同时,我们也会邀请BAT的大牛分享原创!
目录
相关文章推荐
复利大王  ·  好牛的幼儿园 ·  23 小时前  
复利大王  ·  老同学中捞一捞能不能找到免费P友 ·  23 小时前  
鸿洋  ·  务必立即拿下软考证(政策红利) ·  昨天  
复利大王  ·  冷暴力女王,翻车了 ·  昨天  
复利大王  ·  手握25w华子股票,躺平了 ·  昨天  
51好读  ›  专栏  ›  复利大王

【移动开发】Freeline - Android平台上的秒级编译方案

复利大王  · 公众号  · android  · 2016-12-05 12:25

正文

请到「今天看啥」查看全文



inc-code-task介绍


从上到下分别为:


check-r-change:


(校验R文件MD5是否发生变化),若发生变化则把新的R.java加入变更列表

begin-code-transaction:


该过程会把代码增量所必需的工作空间进行备份,若下面其中一个过程发生错误,则会把整个过程中构建的产物进行事务回滚


javac:


把扫描出来的java变更集合,进行编译,若存在dependency (上面例子为common工程)也在构建,则挂起,等待前置任务javac构建完毕后再往下执行


buck-dx:


这里实际上是把上面编译后的class文件变成dex文件,这里用“buck-”描述是因为该dx工具是从Buck中提取出来,经实测比Android原生的dx工具快40%左右


buck-smart-dex:


同上,该工具在buck工具中提取而得,目的是使上一步打出来的dex体积进一步减小,最后生成的dex则为该工程该次增量dex构建的最终结果。


inc-res-task介绍


begin-res-transaction:


该过程会把资源增量所必需的工作空间进行备份,若下面其中一个过程发生错误,则会把整个过程中构建的产物进行事务回滚


merge xml:


若更改的文件在其他子工程也存在,以mPaas架构为例,存在api,biz,build,或tools,这些工程可能会存在同名的xml文件,这种情况需要对这些xml文件内对应的节点进行合并


merge ids:


若上面gen-r 阶段发现R的md5发生过变更,或更改的文件集合里面有ids.xml或public.xml,则把目标目录里面的ids.xml及public.xml与新变更的ids.xml 与public.xml进行xml节点合并。


gen id files:


该过程是实现资源增量的关键,该过程会通过最后一次构建的资源包,反向生成
ids.xml及public.xml,该两个文件在构建增量资源包时候参与编译,可以使得
最后构建出来的资源包的内对于的资源ID与前一次构建的资源包保持一致,该过程原理后面篇幅会详细介绍。


build-inc-res:


该过程会把上面scan过程扫描出来的资源变更集合参与作为参数传入我们自己改写过的increment版本的Aapt,该工具主要完成几个事情:


1.构建增量包,生成最终的资源包时候,仅仅包含编译后的变更资源集及“resources.arsc” 与 “AndroidManifest.xml”;


2.兼容mPaas架构Base Package id 问题;


3.根据ids.xml及public.xml生成保持id值与前一次构建结果里面的id值相同,若该任务有前置的资源任务(上面例子为common),则等待其前置增量资源任务先构建完毕,最后构建出来的包以“.pack”结尾。


多级缓存


在代码变更方面,Freeline在各个工程的Class,dex层面加入了缓存,已经编译过的java文件,直接从增量工作空间里面的的Class pool获取,已经dx过的Class文件,会直接从dex pool中获取,最后实现的效果是,每次增量构建都是一个全新的流程,此前的修改不会参与到本次增量编译过程,不存在LayoutCast方案随着修改文件的增多越来越慢的问题。




在资源变更方面,Freeline会在每次增量包构建后,把增量修改的资源文件与手机端对应的文件进行一次sync同步,每次资源增量构建范围仅仅是本次修改的集合,此前的修改均在此前的sync同步过程中同步至手机端。与代码变更一样,不需要构建此前修改的增量集合。



加入多级缓存及多任务并发策略后数据对比:




增量范围最小化


Freeline会尽可能把增量的范围缩小到单次修改对应的必须要更改的文件集合,不定期与手机端进行同步,以减少随着修改范围增大带来的性能损耗。


代码层面,运用了上面提到的多级缓存,每次仅仅编译本次修改的文件,此前修改过的文件不在本次编译范围。


资源层面,我们为了尽可能降低增量包的体积及构建成本,在aapt的基础上,拓展了一个叫IncrementAapt的工具,并把其编译成linux,mac,windows三个不同平台以做平台兼容,该工具会根据修改的资源文件,及最后一次资源构建结果,构建出对应的增量包,该增量包仅仅含变更的资源集合,且进行过7-zip压缩,大小视更改修改量而定,一般情况只有数百kb。极大程度降低打资源包及最后tcp传输的耗时。


懒加载


Freeline 把任务尽可能延后到真正需要的时候进行,例如对R文件的javac编译,若仅仅修改资源文件,即便是新增了资源文件,如:加了新的id,新的图片,layout等,触发了新的R文件与旧的R文件的id集合不一致,但此如果没有修改过java文件,则不会触发对R文件的编译,也就是如果只修改资源,没有更改过java代码的话,不管实际上应用的id集合是否已经变更,Freeline会以极小的代价构建出增量的资源包,推送至手机,直接在当前的Actvity刷新,不需要重启进程。对于新的R文件的编译,会延后到该工程有java文件更改才执行,这样也保证代码里面真正需要R文件新增的id值的时候,能找到对应的值,在没有代码更改前,进程无需重启,加快刷新效率。


可调试


Android studio instant-run 因采用的是Hack method 的方案,存在被修改的方法无法调试问题,LayoutCast构建的增量Class,在Debug调试下也存在参数值无法显示的问题,Freeline在该点上进行了处理,使得增量构建的类文件与全量构建一致,不影响日常调试。


基于长连接无安装式动态替换


无安装式动态替换与LayoutCast及Android Stduio2.0 instant-run一致,也是该两种增量构建方案的最大的优点,整个构建过程不需要重新安装app,动态替换代码及资源,省去了安装app及重启进程进入对应界面的过程。整个交互流程图见下:




1.phone端会架设一个tcp socket作为服务器。


2.pc端会与手机端进行socket连接。


3.pc端与phone端会通过自定义协议进行交互,pc端会询问phone状态,比如获取手机端基线包版本,sdk版本号,当前手机是否支持资源增量,当前Activity名字等等,后续传输增量包,手机端向pc端返回增量构建结果等,整个通讯过程,均会沿用同一条长连接进行。


4.在同步完增量包后,phone端会根据当前变化是代码变化还是仅仅res变化来决定下一步操作,若仅仅res变化,则直接restart 整个Activity栈里面的Activity,若存在代码变更,则直接重启当前进程,由于Android系统Activity栈的管理,进程被杀若Activity栈还存在Activity,则在该app重启时候,会沿用原来的栈顺序重新创建这些Activity。最终的结果,重启后,界面就会出现最后显示的Activity,(这里有特殊情况,如果该Activity的launchmode设置的是singleTask,或singeInstance,则重启后除了最后的这个Activity,堆栈内的其他Activity均会被清空,这涉及到Android对Activity的管理机制问题,这里不细说,有兴趣的同学可以到自行google。)而按返回键后UI也会顺着原来栈里的Activity顺序显示。


基线对齐触发机制


Freeline会在下面情况重新构建基线包:


1.在git pull 或 一次性修改大量的文件情况下,会导致增量包体积大增,影响后期传输及手机重启后对增量包进行dexopt的速度,考虑到这种情况毕竟是少数,没必要为一次的变更影响后期的增量构建速度。


2.无法依赖增量实现的修改:修改AndroidManifest.xml,更改第三方jar引用,
依赖编译期切面,注解或其他代码预处理插件实现的功能等。


3.更换调试手机或同一调试手机安装了与开发环境不一致的安装包。

由于在重建基线包前,可能已经进行了若干次的增量构建,故在重建基线包时候,要把这些增量构建对应的module进行全量构建,以使得最新的基线包包含了所有过去的修改。整个流程如下图:(A,B, C 分别为3个不同子工程)



head 作为指针,指向最新的基线包状态,base为对应初始的基线状态,在经过3次增量构建,手机端内app的状态会变成base + 3次增量的结果,上面例子里面,3次增量构建涉及A,B,C 3个Module,那么,在触发基线包对齐过程中,会对A ,B,C 按照原来的全量构建方式进行构建,与增量包构建一样,全量包的构建顺序会按照A,B,C前后的依赖关系按顺序进行,位于同层级的工程会进行并发构建,构建完毕后会重新安装至手机,在此之后,手机端内app以全量的方式包含A,B,C的修改,此前的3个增量包会在覆盖安装后第一次启动中被清除,此时基线指针head会从最初的base指向最新的base(with new A,B,C),至此,整个基线对齐就完成了,若中间发生异常,则在下次运行时候仍然会进行一次基线对齐过程,保证手机端安装上最新的全量包。


基线对齐的校验机制


上面的介绍的是基线对齐 的整体思路,下面介绍一下校验部分的关键思路:







请到「今天看啥」查看全文


推荐文章
复利大王  ·  好牛的幼儿园
23 小时前
复利大王  ·  老同学中捞一捞能不能找到免费P友
23 小时前
复利大王  ·  冷暴力女王,翻车了
昨天
复利大王  ·  手握25w华子股票,躺平了
昨天
蔡老师国学  ·  你的死工资,正在拖垮你
7 年前
人生研究所  ·  最好的生活,是随遇而安
7 年前