這個多是做爲 Android 開發想要作插件開發的時候最關心的事,咱們今天看看如何去擴展 Android Gradle Plugin(如下簡稱 AGP)java
咱們擴展 AGP 的方式有兩種:android
其中,第一種方式是咱們常見的方式,咱們常常會使用 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
咱們這一節的目的是在咱們的 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 文件:
能夠看見咱們須要的文件已經打進去了。
那麼對於其餘 Task 咱們依然能夠如法炮製,在 Variants 迭代的過程當中,咱們能先拿到這些 TaskProvider,而後調用 configure 方法,在 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」