千锋教育-做有情怀、有良心、有品质的职业教育机构

手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

当前位置:首页  >  技术干货  > Gradle Transform到底是什么怎么用?

Gradle Transform到底是什么怎么用?

来源:千锋教育
发布人:xqq
时间: 2023-10-13 12:00:43 1697169643

一、Gradle Transform到底是什么

Gradle Transform是Android官方提供给开发者在项目构建阶段(.class -> .dex转换期间)用来修改.class文件的一套标准API,即把输入的.class文件转变成目标字节码文件,目前比较经典的应用是字节码插桩、代码注入等。

二、Gradle Transform怎么用

1、在build.gradle文件中添加Gradle插件依赖

buildscript {    dependencies {        classpath 'com.android.tools.build:gradle:x.x.x'        // 其他插件依赖    }}apply plugin: 'com.android.application' // 或其他所需插件

2、编写Transform类

编写Transform类,在其中实现对Java字节码进行的修改。Transform类需要继承自Transform接口并实现其两个方法:

public class MyTransform extends Transform {   @Override   public String getName() {       return "myTransform";   }   @Override   public Set getInputTypes() {       return TransformManager.CONTENT_CLASS;   }   @Override   public Set getScopes() {       return TransformManager.SCOPE_FULL_PROJECT;   }   @Override   public boolean isIncremental() {       return false;   }   @Override   public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {       // 实现Transform逻辑   }}

3、配置Transform

在build.gradle文件中配置Transform,将其作为编译期间的一个任务执行:

android {    ...    // 配置Transform    transformClassesWithMyTransformForDebug {        // 可选配置项,如下所示        // enable false        // ignoreWarnings true        // enableTransformForJar false    }}dependencies {    ...}

完成以上步骤后,Gradle会在编译期间执行Transform对Java字节码进行修改,从而实现各种自动生成代码、字节码增强等功能。

三、Transform编写模板

1、无增量编译

AspectJTransform.groovy代码如下:

class AspectJTransform extends Transform {    final String NAME =  "JokerwanTransform"    @Override    String getName() {        return NAME    }    @Override    Set getInputTypes() {        return TransformManager.CONTENT_CLASS    }    @Override    Set getScopes() {        return TransformManager.SCOPE_FULL_PROJECT    }    @Override    boolean isIncremental() {        return false    }      @Override    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {        super.transform(transformInvocation)        // OutputProvider管理输出路径,如果消费型输入为空,你会发现OutputProvider == null        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();        transformInvocation.inputs.each { TransformInput input ->            input.jarInputs.each { JarInput jarInput ->                // 处理Jar                processJarInput(jarInput, outputProvider)            }            input.directoryInputs.each { DirectoryInput directoryInput ->                // 处理源码文件                processDirectoryInputs(directoryInput, outputProvider)            }        }    }    void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {        File dest = outputProvider.getContentLocation(                jarInput.getFile().getAbsolutePath(),                jarInput.getContentTypes(),                jarInput.getScopes(),                Format.JAR)                        // to do some transform                // 将修改过的字节码copy到dest,就可以实现编译期间干预字节码的目的了                FileUtils.copyFiley(jarInput.getFile(), dest)    }    void processDirectoryInputs(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {        File dest = outputProvider.getContentLocation(directoryInput.getName(),                directoryInput.getContentTypes(), directoryInput.getScopes(),                Format.DIRECTORY)        // 建立文件夹                FileUtils.forceMkdir(dest)                // to do some transform                // 将修改过的字节码copy到dest,就可以实现编译期间干预字节码的目的了                FileUtils.copyDirectory(directoryInput.getFile(), dest)    }}

2、有增量编译

AspectJTransform.groovy代码如下:

class AspectJTransform extends Transform {    final String NAME = "JokerWanTransform"    @Override    String getName() {        return NAME    }    @Override    Set getInputTypes() {        return TransformManager.CONTENT_CLASS    }    @Override    Set getScopes() {        return TransformManager.SCOPE_FULL_PROJECT    }    @Override    boolean isIncremental() {        return true    }    @Override    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {        super.transform(transformInvocation)        boolean isIncremental = transformInvocation.isIncremental()        // OutputProvider管理输出路径,如果消费型输入为空,你会发现OutputProvider == null        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()        if (!isIncremental) {            // 不需要增量编译,先清除全部            outputProvider.deleteAll()        }        transformInvocation.getInputs().each { TransformInput input ->            input.jarInputs.each { JarInput jarInput ->                // 处理Jar                processJarInputWithIncremental(jarInput, outputProvider, isIncremental)            }            input.directoryInputs.each { DirectoryInput directoryInput ->                // 处理文件                processDirectoryInputWithIncremental(directoryInput, outputProvider, isIncremental)            }        }    }    void processJarInputWithIncremental(JarInput jarInput, TransformOutputProvider outputProvider, boolean isIncremental) {        File dest = outputProvider.getContentLocation(                jarInput.getFile().getAbsolutePath(),                jarInput.getContentTypes(),                jarInput.getScopes(),                Format.JAR)        if (isIncremental) {            // 处理增量编译            processJarInputWhenIncremental(jarInput, dest)        } else {            // 不处理增量编译            processJarInput(jarInput, dest)        }    }    void processJarInput(JarInput jarInput, File dest) {        transformJarInput(jarInput, dest)    }    void processJarInputWhenIncremental(JarInput jarInput, File dest) {        switch (jarInput.status) {            case Status.NOTCHANGED:                break            case Status.ADDED:            case Status.CHANGED:                // 处理有变化的                transformJarInputWhenIncremental(jarInput.getFile(), dest, jarInput.status)                break            case Status.REMOVED:                // 移除Removed                if (dest.exists()) {                    FileUtils.forceDelete(dest)                }                break        }    }    void transformJarInputWhenIncremental(JarInput jarInput, File dest, Status status) {        if (status == Status.CHANGED) {            // Changed的状态需要先删除之前的            if (dest.exists()) {                FileUtils.forceDelete(dest)            }        }        // 真正transform的地方        transformJarInput(jarInput, dest)    }    void transformJarInput(JarInput jarInput, File dest) {            // to do some transform                // 将修改过的字节码copy到dest,就可以实现编译期间干预字节码的目的了        FileUtils.copyFile(jarInput.getFile(), dest)    }    void processDirectoryInputWithIncremental(DirectoryInput directoryInput, TransformOutputProvider outputProvider, boolean isIncremental) {        File dest = outputProvider.getContentLocation(                directoryInput.getFile().getAbsolutePath(),                directoryInput.getContentTypes(),                directoryInput.getScopes(),                Format.DIRECTORY)        if (isIncremental) {            // 处理增量编译            processDirectoryInputWhenIncremental(directoryInput, dest)        } else {            processDirectoryInput(directoryInput, dest)        }    }    void processDirectoryInputWhenIncremental(DirectoryInput directoryInput, File dest) {        FileUtils.forceMkdir(dest)        String srcDirPath = directoryInput.getFile().getAbsolutePath()        String destDirPath = dest.getAbsolutePath()        Map fileStatusMap = directoryInput.getChangedFiles()        fileStatusMap.each { Map.Entry entry ->            File inputFile = entry.getKey()            Status status = entry.getValue()            String destFilePath = inputFile.getAbsolutePath().replace(srcDirPath, destDirPath)            File destFile = new File(destFilePath)            switch (status) {                case Status.NOTCHANGED:                    break                case Status.REMOVED:                    if (destFile.exists()) {                        FileUtils.forceDelete(destFile)                    }                    break                case Status.ADDED:                case Status.CHANGED:                    FileUtils.touch(destFile)                    transformSingleFile(inputFile, destFile, srcDirPath)                    break            }        }    }    void processDirectoryInput(DirectoryInput directoryInput, File dest) {        transformDirectoryInput(directoryInput, dest)    }    void transformDirectoryInput(DirectoryInput directoryInput, File dest) {            // to do some transform                // 将修改过的字节码copy到dest,就可以实现编译期间干预字节码的目的了        FileUtils.copyDirectory(directoryInput.getFile(), dest)    }    void transformSingleFile(File inputFile, File destFile, String srcDirPath) {        FileUtils.copyFile(inputFile, destFile)    }}

延伸阅读1:TransformInput

TransformInput是指输入文件的一个抽象,包括:

DitectoryInput集合:是指以源码的方式参与项目编译的所有目录结构及其目录下的源码文件JarInput集合:是指以jar包方式参与项目编译的所有本地jar包和远程jar包(此处的jar包包括aar)
声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。
10年以上业内强师集结,手把手带你蜕变精英
请您保持通讯畅通,专属学习老师24小时内将与您1V1沟通
免费领取
今日已有369人领取成功
刘同学 138****2860 刚刚成功领取
王同学 131****2015 刚刚成功领取
张同学 133****4652 刚刚成功领取
李同学 135****8607 刚刚成功领取
杨同学 132****5667 刚刚成功领取
岳同学 134****6652 刚刚成功领取
梁同学 157****2950 刚刚成功领取
刘同学 189****1015 刚刚成功领取
张同学 155****4678 刚刚成功领取
邹同学 139****2907 刚刚成功领取
董同学 138****2867 刚刚成功领取
周同学 136****3602 刚刚成功领取
相关推荐HOT