字节码插桩技术,通过AOP的手段实现业务

可以实现的功能:
1.统一处理事件点击,点击防抖
2.日志打点,可以处理自己的activity或者是三方SDK的activity
3.性能监控、动态权限控制等

先看一看android打包过程:

其中需要关注的是中间生成的class文件,通过ASM修改原class文件,生成新的class文件,再使用新的class文件打包到dex文件中;

实现过程
总体思路,遍历项目中所有的.class文件,过滤出需要处理的class文件,在需要处理的方法中,通过ASM插入字节码。

具体实现:
androidstudio使用gradle编译打包项目时,都是通过一个个transform处理的,并且我们可以自定义transform去获取所有class文件的引用,自定义transform需要依赖GradlePlugin,所以首先需要创建一个GradlePlugin;之后再通过ASM插入字节码。

自定义的gradle插件写好后,可以通过gradle构建命令,构建并发布插件,然后就可以在app中使用了

ASM是一套开源框架,常用的几个API如下:
ClassReader,负责解析.class文件中的字节码,并将所有字节码传递给ClassWriter;
ClassVisitor,负责访问class文件中的各个元素,解析class文件结构,然后自动调用内部相应的FieldVisitor或者MethodVisitor方法,进一步解析或者修改class文件内容。
ClassWriter,继承自ClassVisitor,它是生成字节码的工具类,负责将修改后的字节码输出为byte数组。

需要注意的点:
AGP升级到7之后,maven插件不再可用,要换成apply plugin: 'maven-publish'
对应的下面的task也需要换,整体的文件如下

apply plugin: 'groovy'
apply plugin: 'maven-publish'

dependencies {

    implementation gradleApi()
    implementation localGroovy()

    implementation 'com.android.tools.build:gradle:7.1.2'


    //ASM相关依赖
    implementation 'org.ow2.asm:asm:9.1'
    implementation 'org.ow2.asm:asm-commons:9.1'
}


publishing {
    publications {
        mavenJava(MavenPublication) {
            //定义插件的在本地 maven 中的 id
            groupId 'danny.lifecycle.plugin'
            artifactId 'asm_lifecycle_plugin'
            //定义插件的在本地 maven 中的版本号
            version '1.0.0'
            from components.java
        }
    }
    repositories {
        maven {
            // 发布位置
            url uri('../asm_lifecycle_repo')
        }
    }
}

实测中发现,Transform类已经废弃,而且使用FileUtils时也找不到,导致demo最终没有成功运行。