• Transform介绍 - 源码分析(3)


    1. Transform 与 Task 的关系

    Project是由Task组成,每个 Task 负责完成一个基本工作,例如 javac 编译 task,transform 也是依靠 Task(TransformTask ) 执行的,在配置阶段, Gradle 会为注册的 Transform 创建对应的 Task(TransformTask )

    而 Task 的依赖关系是通过 TransformTask 的输入输出关系隐式确定的,TransformManager 通过 TransformStream 链接各个 TransformTask 的输入输出,进而控制 Transform 的依赖关系顺序

    我们先从 Plugin 的注册 transform 开始:

    // MyPlugin.groovy
    void apply(Project project){
        def baseExt = project.extensions.getByType(BaseExtension.class)
        baseExt.registerTransform(new MyTransform2(project))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    接着进入 BaseExtension 看看,这个类维护了所有 Transform

    // com.android.build.gradle\BaseExtension.kt
    fun registerTransform(transform: Transform, vararg dependencies: Any) {
        _transforms.add(transform)
        _transformDependencies.add(listOf(dependencies))
    }
    
    override val transforms: List<Transform>
            get() = ImmutableList.copyOf(_transforms)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    查看 transforms变量的调用,找到LibraryTaskManager.java,我们看看该类

    // com.android.build.gradle.internal\LibraryTaskManager.java
    public class LibraryTaskManager extends TaskManager<LibraryVariantBuilderImpl, LibraryVariantImpl> {
        @Override
        protected void doCreateTasksForVariant(..){
            ...
             // ----- External Transforms -----
            // apply all the external transforms.
            List<Transform> customTransforms = extension.getTransforms();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    发现在 doCreateTasksForVariant 方法中有调用,该类的父类是 TaskManager,感兴趣的可以去翻翻它们看看,我这里将方法调用链进行列举

    // com.android.build.gradle.internal
    TaskManager.java
    -> doCreateTasksForVariant() // 【注1】
    -> createTasksForVariant()
    -> createTasks()
    // com.android.build.gradle.internal.plugins
    BasePlugin.java
    -> createAndroidTasks()
    -> createTasks() // 【注2】project.afterEvaluate()中调用 createAndroidTasks()
    -> basePluginApply()
    -> apply()// 【注3】
    // com.android.build.gradle.internal.plugins
    LibraryPlugin.java // 【注4】
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2. Transform 的注册

    【注1】执行 doCreateTasksForVariant 抽象方法,具体到实现类为LibraryTaskManager,Library 模块仅只支持使用 Scope.PROJECT 作用域。自定义插件不涉及ApplicationTaskManager

    // com.android.build.gradle.internal\LibraryTaskManager.java
    public class LibraryTaskManager extends TaskManager<LibraryVariantBuilderImpl, LibraryVariantImpl> {
        ...
        @Override
        protected void doCreateTasksForVariant(..){
            ...
             // ----- External Transforms -----
            // apply all the external transforms.
            List<Transform> customTransforms = extension.getTransforms();
            ...
            for (int i = 0, count = customTransforms.size(); i < count; i++) {
                Transform transform = customTransforms.get(i);
                // Library 模块仅只支持使用 Scope.PROJECT 作用域
                Sets.SetView<? super Scope> difference =
                		Sets.difference(transform.getScopes(), TransformManager.PROJECT_ONLY);
                ...
                // 将 transfrom 添加到 TransformManager 中
                transformManager.addTransform(
                        taskFactory,
                        libraryVariant,
                        transform,...)
            }
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    我们进入 TransformManager 看看添加 transform 的方法,看到 TransformTask 的 TaskName 有相应的规范transform[InputTypes]with[name]For[componentName]

    // com.android.build.gradle.internal.pipeline
    public class TransformManager extends FilterableStreamCollection {
        ...
        public <T extends Transform> Optional<TaskProvider<TransformTask>> addTransform(..){
            ...
            // TaskName = transform[InputTypes]with[name]For[componentName]
            String taskName = creationConfig.computeTaskName(getTaskNamePrefix(transform), "");
            ...
        }
        
        ...
        // TaskName 前缀 :transform[InputTypes]with[name]For
        static String getTaskNamePrefix(@NonNull Transform transform) {
            StringBuilder sb = new StringBuilder(100);
            sb.append("transform");
            sb.append(
                    transform
                            .getInputTypes()
                            .stream()
                            .map(
                                    inputType ->
                                            CaseFormat.UPPER_UNDERSCORE.to(
                                                    CaseFormat.UPPER_CAMEL, inputType.name()))
                            .sorted() // Keep the order stable.
                            .collect(Collectors.joining("And")));
            sb.append("With");
            StringHelper.appendCapitalized(sb, transform.getName());
            sb.append("For");
            return sb.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3. TransformTask 的输入输出

    public abstract class TransformTask extends StreamBasedTask {
        //...
     	@Input
        @NonNull
        public Set<QualifiedContent.ContentType> getInputTypes() {
            return transform.getInputTypes();
        }
        ...
        @OutputDirectory
        @Optional
        @NonNull
        public abstract DirectoryProperty getOutputDirectory()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通过 @Input 和 @OutputDirectory 将 Transform 与 TransformTask 进行关联

    再看看 transform 方法,每个 TransformTask 内部都包含一个 CreationAction,执行 TransformTask 就是执行该 Action,用户通过 @TaskAction 添加默认 Action

      @TaskAction
        void transform(final IncrementalTaskInputs incrementalTaskInputs)
                throws IOException, TransformException, InterruptedException {
            ...
            u analyticsService = getAnalyticsService().get();
            ...
            analyticsService.recordBlock(
                    ExecutionType.TASK_TRANSFORM,
                    executionInfo,
                    getProjectPath().get(),
                    getVariantName(),
                    new Recorder.VoidBlock() {
                        @Override
                        public void call() {
                            ...
                             transform.transform(
                                    new TransformInvocationBuilder(context)
                                            .addInputs(consumedInputs.getValue())
                                            .addReferencedInputs(referencedInputs.getValue())
                                            .addSecondaryInputs(changedSecondaryInputs.getValue())
                                            .addOutputProvider(
                                                    outputStream != null
                                                            ? outputStream.asOutput()
                                                            : null)
                                            .setIncrementalMode(isIncremental.getValue())
                                            .build());
                        }
                    }
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  • 相关阅读:
    Gradio入门到进阶全网最详细教程[一]:快速搭建AI算法可视化部署演示(侧重项目搭建和案例分享)
    将VS工程转为pro工程及VS安装Qt插件后没有create basic .pro file菜单问题解决
    计算机毕业设计Java高校教师科研文献管理系统(源码+系统+mysql数据库+lw文档)
    tdk-lambda电源主要应用
    离子苯基卟啉交联聚苯乙烯微球/表面修饰温敏型二乙基二硫代氨基甲酸钠相关研究
    浅析SpringBoot框架常见未授权访问漏洞
    机器学习DAYX:线性回归与逻辑回归
    想知道有没有拍照转文字的软件?这3款工具职场人士必备
    【云原生之Docker实战】使用Docker部署draw.io思维导图工具
    RESTful 接口设计
  • 原文地址:https://blog.csdn.net/qq_37776700/article/details/127681944