所谓字节码插桩就是在编译成字节码的文件中插入代码。那字节码插桩到底有什么好处,字节码插桩可以设置埋点,例如管理应用打开的activity,首先想到的做法是在打开一个activity的时候将activity实例存放到一个全局List中。其次就是建立一个BaseActivity,在BaseActivity中完成统计的工作,但是对于不同Activity类型(Activity,FragmentActivity等)还是很麻烦的。另外无论是第一种方式还是第二种方式都无法把第三方lib库中的activity进行管理的。在这个时候使用字节码插桩的方式就变的简单了。使用插桩的方式寻找所有class类中的onCreate方法,在onCreate方法中插入管理activity的代码,这样就一劳永逸了。插桩还有另外一个用途就是用于android的热修复。下面讲讲如何在android项目中实行插桩呢?
首先要知道android的apk的打包过程:
这幅图是android项目生成apk的打包过程,android的apk打包过程是经过一个又一个的gradle任务进行的。如下图:
我们可以在class文件打包成dex文件的时候寻找所有class文件中onCreate方法。然后在这个方法里面加入功能。
上面说的理论看起来很完美,但是对于直接在字节码中写入字节码代码,这是一件非常困难的事情,如果一个字节码改不好,就可能运行不起来了。那么这样如何是好呢,这里我们可以使用ASM,ASM是什么?AMS是一个字节码操控框架,它可以动态生成类,也可以增加类的功能。ASM有几个类:ClassReader用于读取class字节码,并进行解析。ClassVisitor将ClassReader中分析内容进行处理,在这里对现有的class做修改。ClassWriter用于将新修改的内容打包成新的class文件。
那么我们该如何利用ASM实现呢?这里我们需要依托自定义的gradle插件,这里借助别人写的一段代码:
所有的插件都必须实现‘Plugin’方法 ,apply是插件的入口,当调用:“apply plugin”就会调用apply方法。插件之前都是使用groovy语言实现的,现在也支持kotlin语言了。在android中注册一个我们实现的transform,在transform中可以接收输入流,tranform中可以自定义要接收的输入流,这里我们主要是接受class文件,所以就只过滤class文件就可以了:
这样我们只要处理class文件就可以了:
在这里我们就利用了ASM的类对class文件进行处理。