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」
公衆號

相關文章
相關標籤/搜索