Gradle Transform

来源:互联网 发布:游戏帧数测试软件 编辑:程序博客网 时间:2024/06/04 01:36

概述

Gradle Transform是Android官方提供给开发者在项目构建阶段即由class到dex转换期间修改class文件的一套api。目前比较经典的应用是字节码插桩、代码注入技术。

基础

  1. TransformInput:所谓Transform就是对输入的class文件转变成目标字节码文件,TransformInput就是这些输入文件的抽象。目前它包括两部分:DirectoryInput集合与JarInput集合。
  2. DirectoryInput:它代表着以源码方式参与项目编译的所有目录结构及其目录下的源码文件,可以借助于它来修改输出文件的目录结构、已经目标字节码文件。
  3. JarInput:它代表着以jar包方式参与项目编译的所有本地jar包或远程jar包,可以借助于它来动态添加jar包。
  4. TransformOutputProvider:它代表的是Transform的输出,例如可以通过它来获取输出路径。
  5. 目前Transform包含如下方法:
    这里写图片描述

    • getName:用于指明本Transform的名字,也是代表该Transform的task的名字
    • getInputTypes:用于指明Transform的输入类型,可以作为输入过滤的手段。在TransformManager定义了如下的几种类型:
    public static final Set<ContentType> CONTENT_CLASS = ImmutableSet.of(CLASSES);public static final Set<ContentType> CONTENT_JARS = ImmutableSet.of(CLASSES, RESOURCES);public static final Set<ContentType> CONTENT_RESOURCES = ImmutableSet.of(RESOURCES);public static final Set<ContentType> CONTENT_NATIVE_LIBS = ImmutableSet.of(        ExtendedContentType.NATIVE_LIBS);public static final Set<ContentType> CONTENT_DEX = ImmutableSet.of(        ExtendedContentType.DEX);public static final Set<ContentType> CONTENT_JACK = ImmutableSet.of(JACK);public static final Set<ContentType> DATA_BINDING_ARTIFACT = ImmutableSet.of(        ExtendedContentType.DATA_BINDING, CLASSES);
    • getScopes:用于指明Transform的作用域,在TransformManager定义了如下的三种种类型:
    public static final Set<Scope> SCOPE_FULL_PROJECT = Sets.immutableEnumSet(        Scope.PROJECT,        Scope.PROJECT_LOCAL_DEPS,        Scope.SUB_PROJECTS,        Scope.SUB_PROJECTS_LOCAL_DEPS,        Scope.EXTERNAL_LIBRARIES);public static final Set<QualifiedContent.ScopeType> SCOPE_FULL_INSTANT_RUN_PROJECT =        new ImmutableSet.Builder<QualifiedContent.ScopeType>()                .addAll(SCOPE_FULL_PROJECT)                .add(InternalScope.MAIN_SPLIT)                .build();public static final Set<Scope> SCOPE_FULL_LIBRARY = Sets.immutableEnumSet(        Scope.PROJECT,        Scope.PROJECT_LOCAL_DEPS);
    • isIncremental:用于指明是否是增量构建。

实践

  1. 新建一个标准的Android项目,在app module下的build.gradle添加如下依赖:

    dependencies {       compile localGroovy()    compile 'com.android.tools.build:transform-api:1.5.0'    compile 'commons-io:commons-io:2.5'}
  2. 采用buildSrc的方式进行开发,并将Transform封装到自定义插件中,如下buildSrc项目结构:
    这里写图片描述

  3. 在该buildSrc下的build.gradle中声明Transform API依赖:

    repositories {    jcenter()}dependencies {    compile 'com.android.tools.build:gradle:2.3.3'}
  4. 继承Transform,并重写transform方法

    package demoimport com.android.build.api.transform.Contextimport com.android.build.api.transform.DirectoryInputimport com.android.build.api.transform.Formatimport com.android.build.api.transform.JarInputimport com.android.build.api.transform.Transformimport com.android.build.api.transform.TransformExceptionimport com.android.build.api.transform.TransformInputimport com.android.build.api.transform.TransformOutputProviderimport com.android.build.gradle.internal.pipeline.TransformManagerimport com.android.build.api.transform.QualifiedContent.Scopeimport com.android.build.api.transform.QualifiedContent.ContentTypeimport org.apache.commons.codec.digest.DigestUtilsimport org.apache.commons.io.FileUtilsimport org.gradle.api.Projectclass PathTransform extends Transform {    Project project    public PathTransform(Project project) {        this.project = project    }    @Override    void transform(        Context context,        Collection<TransformInput> inputs,        Collection<TransformInput> referencedInputs,        TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {        System.out.println("=======================================doPathTransform{ context=${context}, inputs=${inputs}, referencedInputs=${referencedInputs}, outputProvider=${outputProvider}, isIncremental=${isIncremental}")    }    @Override    String getName() {        return PathTransform.simpleName    }    @Override    Set<ContentType> getInputTypes() {        return TransformManager.CONTENT_CLASS    }    @Override    Set<? super Scope> getScopes() {        return TransformManager.SCOPE_FULL_PROJECT    }    @Override    boolean isIncremental() {        return false    }}
  5. 在自定义task或plugin中注册该Transform,注意AppExtension就是app中build.gradle中android块:

    package demoimport org.gradle.api.Pluginimport org.gradle.api.Projectimport com.android.build.gradle.AppExtensionclass PathPlugin implements Plugin<Project> {    @Override    void apply(Project project) {        def android = project.extensions.getByType(AppExtension)        android.registerTransform(new PathTransform(project))        project.task('transformPath') {            doLast {                System.out.println('+++++++++++++++++++++transformPath task')            }        }    }}
  6. 在app module中使用该插件:

    apply plugin: demo.PathPlugin
  7. 命令行gradle assembleDebug执行构建时,会打印log:
    这里写图片描述

结论

从上述实践过程不难发现Gradle Transform更多的是提供一种可以让开发者参与项目构建的机制,而诸如修改字节码等更加具体的细节则需要开发者去实现。

原创粉丝点击