Gradle Transform和ASM

GradleTransform是Android构建过程中用于修改.class文件的API,允许在不修改源码的情况下进行自定义操作,如代码注入和热修复。文章通过ASM库展示了如何在Transform阶段插入字节码,实现方法执行时间的日志打印。ASM是一个强大的字节码操控和分析框架。

Gradle Transform和ASM

本文链接:https://blog.youkuaiyun.com/feather_wch/article/details/131753544


关键词:
transform
asm
org.ow2.asm:asm

项目路径:https://github.com/FeatherHunter/StudyNotes/blob/master/assets/DemoProjects/ASMInject.zip

Trasnform

1、Gradle Transform是什么。😊

  1. Gradle Transform是Android官方提供给开发者在项目构建阶段(.class ->.dex转换期间)用来修改.class文件的一套标准API
  2. 可以在不修改源代码的情况下,对.class文件进行自定义的操作,例如插入字节码,修改注解,替换资源等。
  3. Gradle Transform可以用于实现一些高级的功能,例如热修复,代码注入,AOP等。

2、Gradle构建的阶段

  • 初始化阶段:Gradle会加载项目的配置信息,检查依赖关系,创建任务图等。
  • 编译阶段:Gradle会调用Java编译器将源代码转换成.class文件,并调用AAPT工具将资源文件转换成二进制格式。
  • Transform阶段:Gradle会调用Transform API对输入的.class文件进行自定义的操作,例如插入字节码,修改注解,替换资源等。Transform可以用于实现一些高级的功能,例如热修复,代码注入,AOP等。
  • DEX阶段:radle会调用DX工具将.class文件转换成DEX文件,以适应Android平台的运行环境。
  • 打包阶段:Gradle会调用APK打包器将DEX文件和已编译资源合并成单个APK文件,并对其进行签名和对齐等操作。
  • 安装和运行阶段:Gradle会将APK文件安装到目标设备或模拟器上,并启动应用程序。

3、Transform阶段的资源来自于

  1. class
  2. jar
  3. resources:特指和java平级的resources文件夹中资源。不是Android的res文件。

4、> Task :app:preBuild UP-TO-DATE => 代表最新的没有变化

Transform实战

ASMPlugin.groovy:Plugin插件,apply中注册Transform

class ASMPlugin implements Plugin<Project> {
   
   

    @Override
    void apply(Project project) {
   
   

// 注册Transform ASMTransform
        project.extensions.getByType(AppExtension.class).registerTransform(new ASMTransform())
    }
}

ASMTransform.groovy:

class ASMTransform extends Transform {
// 1、任务的名称
    @Override
    String getName() {
        return "asm";
    }
// 2、可以是Class可以是resources这里只需要Class
    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }
// 3、只对引入插件的模块生效
    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.PROJECT_ONLY
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        TransformOutputProvider outputProvider = transformInvocation.outputProvider
        //清理文件
        outputProvider.deleteAll()

        def inputs = transformInvocation.inputs
        inputs.each {
// 4、因为是transformManager.PROJECT_ONLY 只管当前的src目录,不管jar目录,不需要 it.jarInputs
            def directoryInputs = it.directoryInputs
            directoryInputs.each {
                String dirName = it.name
                File src = it.getFile();
                println("源目录:" + src)
// 5、transform是一个一个执行的,上一个transoform的输出是下一个的输入。
// 源目录:F:\5.Android\Projects\ASMInject\ASMInject\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes
// 目标目录:F:\5.Android\Projects\ASMInject\ASMInject\app\build\intermediates\transforms\asm\debug\0
                String md5Name = DigestUtils.md5Hex(src.absolutePath)
                File dest = outputProvider.getContentLocation(dirName + md5Name, // 必须保证是唯一的
                        it.contentTypes, // 类型
                        it.scopes, // 作用域
                        Format.DIRECTORY);
//根据这些参数,outputProvider.getContentLocation 会返回一个 File 对象,表示这个内容的位置。如果格式是 Format.DIRECTORY ,那么结果是一个目录的文件位置;如果格式是 Format.JAR ,那么结果是一个表示要创建的 jar 包的文件。
                println("目标目录:" + dest)
                println("dirName:" + dirName) // dirName:e47eef71c08b0d42c571e631eb55645c006d92a2
                println("md5Name:" + md5Name) // md5Name:5f3e38731d3c990d7ad79d6404c3b796
                //插桩
                processInject(src, dest);
            }
        }
    }

    void processInject(File src, File dest) {
        String dir = src.absolutePath
        FluentIterable<File> allFiles = FileUtils.getAllFiles(src)
        for (File file : allFiles) {
            println("需要插桩的文件:" + file.name)
            FileInputStream fis = new FileInputStream(file)
            //插桩
            ClassReader cr = new ClassReader(fis)
            // 写出器
           
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值