背景
随着项目中对 APM (Application Performance Management) 越来越关注,诸如像 Debug 日志,运行耗时监控等都会陆陆续续加入到源码中,随着功能的增多,这些监控日志代码在某种程度上会影响甚至是干扰业务代码的阅读,笔者于是查阅有没有一些可以自动化在代码中插入日志的方法,“插桩”就映入眼帘了,本质的思想都是 AOP,在编译或运行时动态注入代码。本文选了一种在编译期间修改字节码的方法,实现在方法执行前后插入日志代码的方式进行一些初步的试探,目的旨在学习这个流程。
概述
交待完背景后,先对接下来要讲的内容做一个简要的说明。因为是编译期间搞事情,所以首先要在编译期间找一个时间点,这也就是标题前半部分 Transform 的内容;找到“作案”地点后,接下来就是“作案对象”了,这里选择的是对编译后的 .class 字节码下手,要到的工具就是后半部分要介绍的 ASM 了。至此,希望读者能对本文要讲的内容有一个初步的印象了。
Transform
官方出品的编译打包签名流程,我们要搞事情的位置就是 Java Compiler 编译成 .class Files 之到打包为 .dex Files 这之间。Google 官方在 Android Gradle 的 1.5.0 版本以后提供了 Transfrom API, 允许第三方自定义插件在打包 dex 文件之前的编译过程中操作 .class 文件,所以这里先要做的就是实现一个自定义的 Transform 进行.class文件遍历拿到所有方法,修改完成对原文件进行替换。
下面说一下如何引入 Transform 依赖,在 Android gradle 插件 1.5 版本以前,是有一个单独的 transform api 的;从 2.0 版本开始,就直接并入到 gradle api 中了。
Gradle 1.5:
Compile ‘com.android.tools.build:transfrom-api:1.5.0’
Gradle 2.0 开始:
implementation 'com.android.tools.build:gradle-api:3.0.1'
每个 Transform 其实都是一个 Gradle task,他们链式组合,前一个的输出作为下一个的输入,而我们自定义的 Transform 是作为第一个 task 最先执行的。
本文是基于 buildSrc 的方式定义 Gradle 插件的,因为只在 Demo 项目中应用,所以 buildSrc 的方式就够了。需要注意一点的是,buildSrc 方式要求 library module 的名称必须为 buildSrc,在实现中注意一下。
废话少说,直接上图:
buildSrc module:
在 buildSrc 中自定义一个基于 Groovy 的插件
[图片上传中…(image.png-d105c7-1556521723794-0)]
在主项目 App 的 build.gradle 中引入自定义的 AsmPlugin
apply plugin: AsmPlugin
最后,在 settings.gradle 中加入 buildSrc module
include ':app', ':buildSrc'
至此,我们就完成了一个自定义的插件,功能十分简陋,只是在控制台输出 “hello gradle plugin",让我们编译一下看看这个插件到底有没有生效。
好了,看到控制台的输出表明我们自定义的插件生效了,“作案地方”就此埋伏完毕。
后面会定义一个 AsmTransform,注册到 AsmPlugin 中,具体代码会在介绍 ASM 的时候贴出来。