Transform

注册Transform

1. //com.android.build.gradle.internal.dsl.BaseAppModuleExtension_Decorated实例
def android = project.extensions.getByType(AppExtension)

AppPlugin appPlugin = getProject().getPlugins().getPlugin(AppPlugin.class)
//com.android.build.gradle.internal.dsl.BaseAppModuleExtension_Decorated实例
def android = appPlugin.getExtension()
    
2. android.registerTransform(new MyClassTransform(project));

Transform执行时机

图解

graph LR
registerTransform-->addTransform("BaseExtension.transforms.add(transform);")-->|TaskManager.createPostCompilationTasks|transformManager.addTransform-->TransformTask.transform
public abstract class BaseExtension implements AndroidConfig {
public void registerTransform(@NonNull Transform transform, Object... dependencies) {
        transforms.add(transform);
        transformDependencies.add(Arrays.asList(dependencies));
}
@Override
@NonNull
public List<Transform> getTransforms() {
    return ImmutableList.copyOf(transforms);
}
public abstract class TaskManager {
public void createPostCompilationTasks(
        @NonNull final VariantScope variantScope) {
        
         // ----- External Transforms -----
        // apply all the external transforms.
        List<Transform> customTransforms = extension.getTransforms();
        List<List<Object>> customTransformsDependencies = extension.getTransformsDependencies();

        for (int i = 0, count = customTransforms.size(); i < count; i++) {
            Transform transform = customTransforms.get(i);

            List<Object> deps = customTransformsDependencies.get(i);
            transformManager.addTransform(
public abstract class TransformTask extends StreamBasedTask {
    @TaskAction
    void transform(final IncrementalTaskInputs incrementalTaskInputs)
            throws IOException, TransformException, InterruptedException {
                                    transform.transform(
                                new TransformInvocationBuilder(context)
                                        .addInputs(consumedInputs.getValue())
                                        ....
                                        .build());

总结

注册之后自定义transform类被包裹在多个对应的transformTask(每个构建变体一个)中,其transform对象为该自定义transform类实例(每个构建变体内部都是同一个实例)

//TransformTask
@TaskAction
void transform(final IncrementalTaskInputs incrementalTaskInputs)
        throws IOException, TransformException, InterruptedException {

对于每个assemble执行的构建变体,都会走一次自定义transform的transform方法,其中的outputProvider路径有区分:

build\intermediates\transforms\MatrixTraceTransform\debug

build\intermediates\transforms\MatrixTraceTransform\release

Transform转换

public interface TransformInput {
    Collection<JarInput> getJarInputs();
    Collection<DirectoryInput> getDirectoryInputs();
}

private void doTransform(TransformInvocation transformInvocation) throws ExecutionException, InterruptedException {
     Collection<TransformInput> inputs = transformInvocation.getInputs();
       for (TransformInput input : inputs) {
            for (DirectoryInput directoryInput : input.getDirectoryInputs()) {
            }

            for (JarInput inputJar : input.getJarInputs()) {
            }
        }

所谓 Transform 就是对输入的 class 文件转变成目标字节码文件,TransformInput 就是这些输入文件的抽象。目前它包括两部分:DirectoryInput 集合与 JarInput 集合。

DirectoryInput 代表以源码方式参与项目编译的所有目录结构及其目录下的源码文件,可以借助于它来修改输出文件的目录结构以及目标字节码文件。

JarInput 代表以 jar 包方式参与项目编译的所有本地 jar 包或远程 jar 包,可以借助它来动态添加 jar 包。

input

build\intermediates\javac\debug\classes\sample\tencent\matrix\BuildConfig.class

Transform 的工作原理

很明显的一个链式结构。其中,红色的 Transform 代表自定义 Transform ,蓝色的代表系统的 Transform 。

每个 Transform 其实都是一个 Gradle 的 Task , Android 编译器中的 TaskManager 会将每个 Transform 串联起来。第一个 Transform 接收来自 javac 编译的结果,以及拉取到本地的第三方依赖和 resource 资源。这些编译的中间产物在 Transform 链上流动,每个 Transform 节点都可以对 class 进行处理再传递到下一个 Transform 。我们自定义的 Transform 会插入到链的最前面,可以在 TaskManager 类的 createPostCompilationTasks 方法中找到相关逻辑

参考

Android动态编译技术:Plugin Transform Javassist操作Class文件

http://tools.android.com/tech-docs/new-build-system/transform-api

Gradle 学习之 Android 插件的 Transform API