Gradle Builds Everything —— Extends Android Gradle Plugin

这个多是做为 Android 开发想要作插件开发的时候最关心的事,咱们今天看看如何去扩展 Android Gradle Plugin(如下简称 AGP)java

咱们扩展 AGP 的方式有两种:android

  1. 利用 ApplicationVariant 和 LibraryVariant 两个类,去扩展咱们的一些功能。
  2. 直接继承 AppPlugin 和 LibraryPlugin 来实现扩展功能。

其中,第一种方式是咱们常见的方式,咱们常常会使用 Gradle 的 DSL 获取到全部的变体。api

applicationVariants.all { variant ->
    ... // Do something
}

applicationVariants 是 AppExtension 里的内容,若是你想配置 Library 工程的话,就使用libraryVariants,这两个 DSL 调用返回的是两种对象的集合,一个是 ApplicationVariant 这个类的集合,一个是 LibraryVariant 的集合,他们都继承于 BaseVariant,咱们看下两个对象的简单声明:app

public interface ApplicationVariant extends ApkVariant, TestedVariant {}

public interface LibraryVariant extends BaseVariant, TestedVariant {
    ...
}

他们统一继承于 BaseVariant(ApkVariant 继承自 BaseVariant),所以能够使用 BaseVariant 得到一些接口。
首先,咱们目前使用的版本是 AGP 3.5.x,BaseVariant 提供了一些主要的 TaskProvider,咱们能拿到相关 Variant 的 TaskProvider 作一些配置,好比咱们关心 Java 编译任务的话,能够使用getJavaCompileProvider这个方法,拿到 TaskProvider<JavaCompile> 对象,而后使用.config方法对这个 Task 进行调用。通常来讲,使用 BaseVariant 的方式能知足基本需求,ide

第二种方式的自定义能力更强大,同时接入会更加复杂,咱们继承了 AppPlugin 就意味着须要子类化 TaskManager 等类,这时候,若是咱们想子类化一些 AGP 提供的任务的话,用这种方式会好不少,若是咱们只想在 AGP 的任务链调用中,插入一个新任务的话,用上第一种方案比较好。gradle

准备

若是咱们已经按照 上一个教程 构建好一个项目的话,咱们能够直接按照这个项目开始。ui

增长自定义的 Java Resources

咱们这一节的目的是在咱们的 APK 中增长本身的任意。咱们须要在 apply 的回调中写逻辑,那么这个处理起来很简单,看如下示例代码:lua

public class AppPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {
        project.afterEvaluate(p -> {
            AppExtension extension = (AppExtension)p.getExtensions().getByName("android");
            Set<? extends BaseVariant> variants = extension.getApplicationVariants();
            configureVariants(project, variants);
        });
    }

    private void configureVariants(Project project, Set<? extends BaseVariant> variants) {
        variants.forEach(it -> {
            TaskProvider<AbstractCopyTask> task = it.getProcessJavaResourcesProvider();
            configureProcessJavaResource(project, task);
        });
    }

    private void configureProcessJavaResource(Project project, TaskProvider<AbstractCopyTask> taskProvider) {
        taskProvider.configure(task -> {
            task.from(project.file("gemini.txt"));
        });
    }
}

AbstractCopyTask.from 的注释以下:spa

/**
     * Specifies source files or directories for a copy. The given paths are evaluated as per {@link
     * org.gradle.api.Project#files(Object...)}.
     *
     * @param sourcePaths Paths to source files for the copy
     */
    CopySourceSpec from(Object... sourcePaths);

那么通过以上修改,咱们就成功的往 JavaResources 任务里面新增了一个 Input 啦。赶忙使用插件

./gradlew clean install

把插件安装到本地,而后在 Android 工程中进行实践吧。
打开咱们上次建立的 Android 工程,而后在app模块中新建刚刚须要的文件,好比我这里使用的是gemini.txt
须要打入包内的文件
最后,执行 Android 工程的任务:

./gradlew clean assembleDebug

完成后,咱们查看下咱们的 APK 文件:

APK

能够看见咱们须要的文件已经打进去了。

那么对于其余 Task 咱们依然能够如法炮制,在 Variants 迭代的过程当中,咱们能先拿到这些 TaskProvider,而后调用 configure 方法,在 Task 真正被建立的时候,会调用到这些方法,咱们只要配置好正确的输入,它就会执行咱们的输出了。

在 AGP 原有的 Task 中接入咱们的 Task

咱们在前面 Gradle Builds Everything —— Task 实例 说过,Task 之间的产物,能够使用 BuildableArtifactsHolder 这个对象链接起来。
由于它是一个产物收集器,在最后 Package 任务须要打包 zip 的过程当中,都是经过这个类把全部已经打出的产物收集起来,最后变成一个 zip 包。

task.outputFile =  variantScope.getArtifacts().createArtifactFile(
                    InternalArtifactType.BUNDLE,
                    BuildArtifactsHolder.OperationType.INITIAL,
                    taskName,
                    bundleName)

咱们目前只能经过继承的方式拿到 VariantScope,同时只能经过子类化 TaskManager 的方式从新编排 Configuration 过程当中的顺序(任务执行顺序咱们反而不用担忧)。经过精心编排好 BuildableArtifactsHolder 的注册顺序,Task 就自动被串联起来了。

后续

后续可能还有关于 Task 输入和输出的高级用法,好比像前文提到的 Artifacts 之类的链接等等。不过到此为止,咱们关于自定义 Gradle 插件的基础用法和主线就全讲完啦。

欢迎关注个人公众号「TalkWithMobile」
公众号