前言
还是我那个90后的老安卓,这算是一篇自吹自擂的自嗨爽文。首先我写这个AndroidAutoTrack Demo的原因很简单,我就单纯觉得很好玩,然后同时其实对于自己的技术水平是会有成长的。我最近下班在优化以前写的自动化埋点。我看过很多文章介绍这个,但是我觉得都是一些入门相关的,很难有一些更深入一点的文章。
Plugin插件或者说Transform,我个人觉得说难其实也不难,但对于新入门的人来说,这个东西非常的不友善,gralde 官方资料都是英文的,然后Gralde Plugin的编写调试又比较繁琐,如果中间碰到了什么问题,如果没人带你一把,你也走进死胡同了。
所以并不是各位看下文章就能完全搞懂这个的,我个人觉得如果没有人带你的情况下,你基本很难学会这个东西。
开始我的表演
一个合格的Transform插件是需要增量编译的功能的,我拿我找到的文章数据给大家做个比较好了。
全量编译的情况下
二次增量编译情况下
我们抛开别的Task,同样一个Transform全量编译的耗时是2784ms,而代码变更增量编译的情况下只有68ms。其中的差距之大也值得各位去把增量编译给写出来了。
当项目后期代码持续不断地增加之后,不可避免的Transform变多了,只要有任意的一个Transform不是增量的,就会导致整个编译Transform过程都变成全量。这个以前我也介绍过,其实有很多系统的Transform任务,比如Shrink和Dex合并等等。
你们想一想哦,一个人优化了1分半的编译时间的话,那么如果团队人员一多,那么岂不就是Kpi美滋滋。
如何去实现一个增编
首先我将Transform流程进行了一次抽象,主要是因为我比较懒,同样代码和功能如果要让我复制黏贴好两遍其实我都不乐意。所以我先对这部分代码进行了梳理,整理出来两个部分,第一就是文件的复制拷贝,第二就是文件的ASM操作。其中我觉第一部分的代码是可以进行整合的,然后就是下面的逻辑了。
先从Transform开始吧,简单的说Transform就是一个输入文件集合Collection<TransformInput>一个输出文件集合TransformOutputProvider的过程。我们先读取原始的class jar,然后我们自己对其进行加工之后生成好另外一部分class jar,最后把这个Transform的输出产物当作下一个Transform的输入产物。当class+jar输入的时候,我会先把整个流数据进行一次copy操作,然后对这个temp文件进行加工,如果asm操作完了,我们就将文件进行覆盖操作。
而在增量编译的情况下,输入流就会发生轻微的变更,TransformInput会告诉我们其中变更的类是什么,其中变更被定义为三种,无论是Jar还是Class都是一样的。
- NOTCHANGED 当前文件不需要处理跳过就行了。
- ADDED、CHANGED 因为我们都是先用temp然后覆盖当前文件,所以采用同样的处理方式。
- REMOVED 删除当前文件夹下的该历史文件。
所以当增编被调用的情况下,我们只是对于上述这四种不同的操作符号进行不同的处理就好了,只要几个if else就能搞定了。
而一般我们在使用asm的时候,我们都只会操作Class文件,然后根据class的文件名+路径对其进行一次简单的判断,当前类是不是我们需要做插桩或者扫描操作的,然后我们会读取这个文件byte数组