Gradle プラグインを作成する

Android Gradle プラグイン(AGP)は、Android アプリケーションの公式ビルドシステムです。さまざまなタイプのソースをコンパイルし、それらをリンクして、Android 搭載の実機またはエミュレータで実行できるアプリにまとめるためのサポートが含まれています。

AGP には、標準のビルドタスクと統合できる新しい手順により、ビルド入力を制御し、機能を拡張するプラグインの拡張ポイントが含まれています。以前のバージョンの AGP には、内部実装から明確に分離された公式 API がありませんでした。バージョン 7.0 以降、AGP には信頼できる公式の安定版 API が用意されています。

AGP API のライフサイクル

AGP は、Gradle 機能のライフサイクルに従って、API の状態を指定します。

  • 内部: 一般公開用ではありません。
  • インキュベーション: 一般公開されていますが、最終版ではありません。つまり、最終版で下位互換性がない可能性があります。
  • 一般公開: 一般公開が可能な安定版です。
  • 非推奨: サポートが終了し、新しい API に置き換えられました。

非推奨ポリシー

AGP は、古い API のサポート終了と、新しい安定版 API と新しいドメイン固有言語(DSL)との置き換えによって進化しています。この進化は複数の AGP リリースに適用されます。詳細については、AGP API / DSL 移行タイムラインをご覧ください。

この移行やその他の方法で AGP API のサポートが終了した場合、現在のメジャー リリースでは引き続き利用できますが、警告が表示されます。サポートが終了した API は、今後のメジャー リリースで AGP から完全に削除されます。たとえば、API が AGP 7.0 で非推奨になっている場合は、そのバージョンで使用することはできますが、警告が生成されます。この API は AGP 8.0 で使用できなくなります。

一般的なビルドのカスタマイズで使用される新しい API の例については、Android Gradle プラグインのレシピをご覧ください。一般的なビルドのカスタマイズの例を示します。新しい API の詳細については、リファレンス ドキュメントをご覧ください。

AGP API アーティファクトに対してコンパイルする

AGP を拡張するカスタム Gradle プラグインまたはビルドロジック(buildSrc ディレクトリ、コンベンション プラグイン モジュール、スタンドアロン プラグイン プロジェクトなど)を作成するには、完全なプラグイン実装アーティファクトではなく、AGP の gradle-api アーティファクトに対してコンパイルします。

gradle-api アーティファクトに対してコンパイルする理由

AGP は、主に次の 2 つのアーティファクトを公開します。

  • com.android.tools.build:gradle-api: 公式の AGP API が含まれています。これには、安定版 API(AndroidComponentsExtension、Variant、公開 DSL インターフェースなど)、インキュベート API(@Incubating のマーク付き)、非推奨 API(@Deprecated のマーク付き)が含まれます。
  • com.android.tools.build:gradle: 内部クラス、ビルドタスク、コンパイラ統合など、完全な AGP ランタイム実装が含まれています。

gradle-api アーティファクトに対してコンパイルすると、主に次のようなメリットがあります。

  • 内部 API を回避する: プラグイン コードが公式 API にのみアクセスするようにします。これにより、内部実装クラス(com.android.build.gradle.internal.*)への偶発的な依存関係を防ぐことができます。内部実装クラスは、AGP のバージョン間で警告なしに変更または削除される可能性があります。
  • ビルドの高速化とフットプリントの縮小: gradle-api アーティファクトの依存関係ツリーは、完全な gradle アーティファクトよりもはるかに小さくなります。これにより、ダウンロード サイズが削減され、クラスパスの汚染が回避され、ビルド ロジックのコンパイルが高速化されます。
  • ランタイムの分離: カスタム プラグインでは、コンパイル時に API 定義のみが必要です。実行時には、Android アプリケーションまたはライブラリ プラグインが適用されると、Android ビルドによって完全な AGP 実装が提供されます。

依存関係を追加する

プラグイン プロジェクトのビルドファイルまたは buildSrc ディレクトリに、gradle-api アーティファクトを依存関係として追加します。gradle-api アーティファクトは、Google の Maven リポジトリで公開されています。アーティファクトを解決するには、ビルドに google() リポジトリが含まれていることを確認します。たとえば、settings.gradle ファイルまたは settings.gradle.kts ファイルの dependencyResolutionManagement.repositories ブロック、プラグインのビルドファイルまたは buildSrc ディレクトリのビルドファイルの repositories ブロックで構成します。

バージョン カタログを使用する場合

プロジェクトでバージョン カタログを使用している場合は、gradle/libs.versions.toml ファイルで gradle-api 依存関係を定義します。

[versions]
androidGradlePlugin = "9.5.0"

[libraries]
android-gradle-plugin-api = { group = "com.android.tools.build", name = "gradle-api", version.ref = "androidGradlePlugin" }

android-gradle-plugin-api カタログ エイリアスは、タイプセーフなアクセサー libs.android.gradle.plugin.api を生成します。

次に、プラグインのビルドファイルの dependencies ブロックに libs.android.gradle.plugin.api を追加します。

Kotlin

dependencies {
    compileOnly(libs.android.gradle.plugin.api)
}

Groovy

dependencies {
    compileOnly libs.android.gradle.plugin.api
}

バージョン カタログを使用しない場合

プロジェクトでバージョン カタログを使用していない場合は、プラグインのビルドファイルで依存関係を直接宣言します。

Kotlin

dependencies {
    compileOnly("com.android.tools.build:gradle-api:9.5.0")
}

Groovy

dependencies {
    compileOnly 'com.android.tools.build:gradle-api:9.5.0'
}

公開を目的としたスタンドアロン プラグインのデフォルトとして、compileOnly 構成オプションを使用します。コンシューマ プロジェクトは AGP を適用し、ビルドスクリプトのクラスパスにランタイム クラスを提供します。compileOnly 構成を使用すると、公開されたプラグインが特定の AGP バージョンにランタイム依存関係をリークするのを防ぎ、コンシューマーのバージョン競合を回避できます。内部ビルドロジック(buildSrc ディレクトリ内のプラグインや、複合ビルド内のコンベンション プラグインなど)を開発する場合は、代わりに implementation 構成オプションを使用します。これらのプラグインはビルド内で実行され、ランタイム クラスパスに AGP が必要です。

Gradle ビルドの基本

このガイドでは、Gradle ビルドシステム全体について説明するわけではありません。Google の API との統合に役立つ、最低限必要な一連のコンセプトについて説明します。また、より詳細な Gradle メイン ドキュメントへのリンクも記載しています。

プロジェクトの構成、ビルドファイルの編集、プラグインの適用、タスクの実行など、Gradle の動作について基本的な知識をお持ちであることを前提としています。AGP に関する Gradle の基本については、ビルドを設定するをご覧ください。Gradle プラグインをカスタマイズするための一般的なフレームワークについては、カスタム Gradle プラグインの開発をご覧ください。

Gradle の遅延型の用語集

Gradle には、「遅延」動作を行うタイプや、重い計算や Task の作成をビルドの後のフェーズに延期するタイプが多数用意されています。これらの型は、多くの Gradle API と AGP API の中核をなしています。次のリストに、遅延実行に関連する主な Gradle タイプとその主なメソッドを示します。

Provider<T>

T 型(「T」は任意の型を意味します)の値を指定します。この値は、実行フェーズ中に get() を使用して読み取るか、map()、flatMap()、zip() メソッドを使用して新しい Provider<S>(「S」は他の型を意味します)に変換できます。get() は、構成フェーズ中に呼び出さないでください。

  • map(): ラムダを受け入れ、S 型の Provider、Provider<S> を生成します。map() のラムダ引数は値 T を受け取り、値 S を生成します。ラムダはすぐには実行されません。代わりに、結果の Provider<S> で get() が呼び出されるまで実行が遅延され、チェーン全体が遅延されます。
  • flatMap(): ラムダを受け入れて Provider<S> を生成しますが、ラムダは値 T を受け取り、Provider<S> を生成します(値 S を直接生成するわけではありません)。構成時に S を特定できず、Provider<S> のみを取得できる場合は、flatMap() を使用します。実際には、map() を使用して Provider<Provider<S>> の結果タイプになった場合は、代わりに flatMap() を使用する必要があることを意味します。
  • zip(): 2 つの Provider インスタンスを組み合わせて新しい Provider を生成できます。値は、2 つの入力 Provider インスタンスの値を組み合わせる関数を使用して計算されます。
Property<T>

Provider<T> を実装するため、T 型の値も提供します。読み取り専用の Provider<T> とは異なり、Property<T> の値を設定することもできます。これには次の 2 つの方法があります。

  • T 型の値が使用可能な場合は、値を直接設定します。演算の遅延は必要ありません。
  • 別の Provider<T> を Property<T> の値のソースとして設定します。この場合、値 T は Property.get() が呼び出されたときにのみ実体化されます。
TaskProvider
Provider<Task> を実装します。TaskProvider を生成するには、tasks.create() ではなく tasks.register() を使用して、タスクが必要なときにのみ遅延インスタンス化されるようにします。flatMap() を使用すると、Task が作成される前に Task の出力にアクセスできます。これは、出力を他の Task インスタンスへの入力として使用する場合に便利です。

プロバイダとその変換メソッドは、タスクの入力と出力を遅延的に、つまりすべてのタスクを事前に作成し、値を解決することを必要とせずに設定するために不可欠です。

プロバイダはタスクの依存関係についての情報も提供します。Task 出力を変換して Provider を作成すると、その Task は Provider の暗黙的な依存関係になり、Provider の値が解決されるたびに(別の Task が必要とする場合など)作成されて実行されます。

次の例では、GitVersionTask と ManifestProducerTask の 2 つのタスクを登録し、実際に必要になるまで Task インスタンスの作成を遅延させています。ManifestProducerTask 入力値は、GitVersionTask の出力から取得した Provider に設定されるため、ManifestProducerTask は暗黙的に GitVersionTask に依存します。

// Register a task lazily to get its TaskProvider.
val gitVersionProvider: TaskProvider =
    project.tasks.register("gitVersionProvider", GitVersionTask::class.java) {
        it.gitVersionOutputFile.set(
            File(project.buildDir, "intermediates/gitVersionProvider/output")
        )
    }

...

/**
 * Register another task in the configuration block (also executed lazily,
 * only if the task is required).
 */
val manifestProducer =
    project.tasks.register(variant.name + "ManifestProducer", ManifestProducerTask::class.java) {
        /**
         * Connect this task's input (gitInfoFile) to the output of
         * gitVersionProvider.
         */
        it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
    }

これら 2 つのタスクは、明示的にリクエストされた場合にのみ実行されます。これは、たとえば、./gradlew debugManifestProducer を実行する場合や、ManifestProducerTask の出力が他のタスクに接続されてその値が必要な場合に、Gradle 呼び出しの一部として行われます。

入力を使用する、出力を生成する、またはその両方を行うカスタムタスクを作成しますが、AGP は独自のタスクへのパブリック アクセスを直接提供しません。これらは実装の詳細であり、バージョンによって変更される場合があります。代わりに、AGP は Variant API を提供し、タスクの出力(ビルド アーティファクト)へのアクセスを可能にします。これにより、ビルド アーティファクトを読み取り、変換できます。詳しくは、このドキュメントの Variant API、アーティファクト、タスクをご覧ください。

Gradle ビルドフェーズ

プロジェクトのビルドは、本質的に複雑でリソースを必要とするプロセスであり、タスク構成の回避、最新のチェック、構成のキャッシュ機能などにより、再現可能な、または不要な計算に費やす作業時間を最小限に抑えることができます。

これらの最適化の一部を適用するには、Gradle スクリプトとプラグインが、Gradle ビルドの各フェーズ(初期化、構成、実行)で厳格なルールに従う必要があります。このガイドでは、構成フェーズと実行フェーズを中心に説明します。すべてのフェーズの詳細については、Gradle ビルド ライフサイクル ガイドをご覧ください。

構成フェーズ

構成フェーズでは、ビルドに含まれるすべてのプロジェクトのビルド スクリプトが評価され、プラグインが適用されて、ビルドの依存関係が解決されます。このフェーズは、DSL オブジェクトを使用してビルドを構成する場合や、タスクとその入力を必要に応じて登録する場合に使用します。

実行がリクエストされるタスクに関係なく、構成フェーズは常に実行されるため、演算がビルド スクリプト自体以外の入力に依存しないように制限することが特に重要です。つまり、適切な Task インスタンスとして、外部プログラムを実行する、ネットワークから読み取る、または実行フェーズまで遅延させることができる長時間の演算を実行することは避けてください。

実施フェーズ

実行フェーズでは、リクエストされたタスクとそれらの依存タスクが実行されます。具体的には、@TaskAction とマークされた Task クラスメソッドが実行されます。タスク実行中は、Provider<T>.get() を呼び出して、入力(ファイルなど)から読み取り、遅延プロバイダを解決できます。この方法で遅延プロバイダを解決すると、プロバイダに含まれるタスク依存関係情報に従って、一連の map() 呼び出しまたは flatMap() 呼び出しが開始されます。タスクは、必要な値をマテリアライズするために遅延実行されます。

Variant API、アーティファクト、タスク

Variant API は、Android Gradle プラグインの拡張メカニズムです。通常はビルド構成ファイルの DSL を使用して設定する、Android ビルドに影響するさまざまなオプションを操作できます。Variant API を使用すると、ビルドによって作成された中間アーティファクトと最終アーティファクト(クラスファイル、マージ マニフェスト、APK / AAB ファイルなど)にアクセスすることもできます。

Android ビルドフローと拡張ポイント

AGP を操作する場合は、一般的な Gradle ライフサイクル コールバック(afterEvaluate() など)を登録したり、明示的な Task 依存関係を設定したりする代わりに、特別に作成された拡張ポイントを使用します。AGP によって作成されたタスクは実装の詳細と見なされ、公開 API として公開されません。Task オブジェクトのインスタンスの取得、Task 名の推測、およびそれらの Task オブジェクトへのコールバックや依存関係の直接追加を試行することは避けてください。

AGP は、Task インスタンスを作成して実行するために次の手順を完了します。これにより、ビルド アーティファクトが生成されます。Variant オブジェクトの作成に関連する主な手順の後には、ビルドの一環として作成された特定のオブジェクトを変更できるコールバックを行います。すべてのコールバックは、(このページで説明しているように)構成フェーズの過程で実施され、高速な実行、ひいては実行フェーズでの適切な Task インスタンスに対する複雑な作業の遅延が必要とされる点に留意することが重要です。

  1. DSL 解析: このタイミングでビルド スクリプトを評価し、android ブロックの Android DSL オブジェクトのさまざまなプロパティを作成して設定します。以降のセクションで説明する Variant API コールバックも、このフェーズで登録されます。

    • finalizeDsl(): コンポーネント(バリアント)作成のためにロックされる前に DSL オブジェクトを変更できるコールバック。VariantBuilder オブジェクトは、DSL オブジェクトに含まれるデータに基づいて作成されます。
  2. DSL ロック: DSL がロックされ、変更できなくなります。

    • beforeVariants(): このコールバックは、VariantBuilder を通じて、作成されるコンポーネントとそのプロパティの一部に影響を与える可能性があります。ビルドフローと生成されるアーティファクトの変更は引き続き可能です。
  3. バリアントの作成: 作成されるコンポーネントとアーティファクトのリストが確定し、変更できなくなります。

    • onVariants(): このコールバックでは、作成された Variant オブジェクトにアクセスし、オブジェクトに含まれる Property 値の値またはプロバイダを設定して、遅延計算できます。
  4. バリアントのロック: バリアントのオブジェクトがロックされ、変更できなくなります。

  5. 作成されたタスク: Variant オブジェクトとその Property 値は、ビルドの実行に必要な Task インスタンスの作成に使用されます。

AGP に AndroidComponentsExtension が導入され、finalizeDsl()、beforeVariants()、onVariants() のコールバックを登録できるようになりました。この拡張機能は、androidComponents ブロックを介してビルド スクリプトで使用できます。

// This is used only for configuring the Android build through DSL.
android { ... }

// The androidComponents block is separate from the DSL.
androidComponents {
   finalizeDsl { extension ->
      ...
   }
}

ただし、ビルド スクリプトは android ブロックの DSL を使用した宣言型構成のみに使用し、カスタムの命令型ロジックは buildSrc ディレクトリまたは外部プラグインに移動することをおすすめします。プロジェクトでプラグインを作成する方法については、Gradle レシピの GitHub リポジトリにある buildSrc サンプルもご覧ください。ビルドファイルで、プラグインが gradle-api アーティファクトに対してコンパイルされるようにします。プラグイン コードからコールバックを登録する例を次に示します。

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            ...
        }
    }
}

以降のセクションでは、使用可能なコールバックと、各コールバックでプラグインがサポートできるユースケースの種類について説明します。

finalizeDsl(callback: (DslExtensionT) -> Unit)

このコールバックでは、ビルドファイル内の android ブロックから情報を解析して、作成された DSL オブジェクトにアクセスし、変更できます。これらの DSL オブジェクトは、ビルドの後のフェーズでバリアントの初期化と構成を行う際に使用されます。たとえば、プログラムで新しい構成を作成する、またはプロパティをオーバーライドすることができますが、構成時にはすべての値が解決される必要があるため、外部入力に依存しないようにしてください。このコールバックの実行が完了すると、DSL オブジェクトは使用できなくなり、オブジェクトへの参照を保持する、または値を変更することができなくなります。

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            extension.buildTypes.create("extra").let {
                it.isJniDebuggable = true
            }
        }
    }
}

beforeVariants()

ビルドのこの段階では、VariantBuilder オブジェクトにアクセスできます。このオブジェクトによって、作成されるバリアントとそれらのプロパティが決定されます。たとえば、特定のバリアントやそれらのテストをプログラムで無効にする、または選択したバリアントのみのプロパティ値(minSdk など)を変更することができます。finalizeDsl() と同様に、指定するすべての値は構成時に解決され、外部入力に依存しないことが必要です。beforeVariants() コールバックの実行が完了した後は、VariantBuilder オブジェクトを変更しないでください。

androidComponents {
    beforeVariants { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

beforeVariants() コールバックは、必要に応じて VariantSelector を受け取ります。これは、androidComponentsExtension の selector() メソッドで取得できます。これを使用すると、コールバック呼び出しに参加するコンポーネントを、名前、ビルドタイプ、プロダクト フレーバーに基づいてフィルタできます。

androidComponents {
    beforeVariants(selector().withName("adfree")) { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

onVariants()

onVariants() が呼び出されるまでに、AGP によって作成されるすべてのアーティファクトはすでに決定されているため、無効にすることはできません。ただし、Variant オブジェクトの Property 属性に設定することで、タスクに使用される値の一部を変更できます。Property の値は AGP のタスクが実行されたときにのみ解決されるため、ファイルやネットワークなどの外部入力からの読み取りなど、必要な演算を行う独自のカスタムタスクからプロバイダに安全に接続できます。

// onVariants also supports VariantSelectors:
onVariants(selector().withBuildType("release")) { variant ->
    // Gather the output when we are in single mode (no multi-apk).
    val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

    // Create version code generating task
    val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
        it.outputFile.set(project.layout.buildDirectory.file("${variant.name}/versionCode.txt"))
    }
    /**
     * Wire version code from the task output.
     * map() will create a lazy provider that:
     * 1. Runs just before the consumer(s), ensuring that the producer
     * (VersionCodeTask) has run and therefore the file is created.
     * 2. Contains task dependency information so that the consumer(s) run after
     * the producer.
     */
    mainOutput.versionCode.set(versionCodeTask.map { it.outputFile.get().asFile.readText().toInt() })
}

生成されたソースをビルドに提供する

プラグインでは、生成された次のようないつかのタイプのソースを提供できます。

追加できるソースの詳細なリストについては、Sources API をご覧ください。

次のコード スニペットは、addStaticSourceDirectory() 関数を使用して ${variant.name} というカスタム ソースフォルダを Java ソースセットに追加する方法を示しています。追加すると、Android ツールチェーンがこのフォルダを処理するようになります。

onVariants { variant ->
    variant.sources.java?.let { java ->
        java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
    }
}

詳細については、addJavaSource のレシピをご覧ください。

次のコード スニペットは、カスタムタスクから生成された Android リソースを含むディレクトリを res ソースセットに追加する方法を示しています。このプロセスは、他のソースタイプでも同様です。

onVariants(selector().withBuildType("release")) { variant ->
    // Step 1. Register the task.
    val resCreationTask =
       project.tasks.register<ResCreatorTask>("create${variant.name}Res")

    // Step 2. Register the task output to the variant-generated source directory.
    variant.sources.res?.addGeneratedSourceDirectory(
       resCreationTask,
       ResCreatorTask::outputDirectory)
    }

...

// Step 3. Define the task.
abstract class ResCreatorTask: DefaultTask() {
   @get:OutputFiles
   abstract val outputDirectory: DirectoryProperty

   @TaskAction
   fun taskAction() {
      // Step 4. Generate your resources.
      ...
   }
}

詳細については、addCustomAsset のレシピをご覧ください。

アーティファクトにアクセスして変更する

AGP では、Variant オブジェクトの基本プロパティを変更できるだけでなく、ビルド中に生成された中間アーティファクトと最終アーティファクトを読み取りまたは変換できる拡張メカニズムも用意されています。たとえば、結合された最終的な AndroidManifest.xml ファイルのコンテンツをカスタム Task で読み取って分析する、またはそのコンテンツをカスタム Task によって生成されたマニフェスト ファイルのコンテンツと完全に置き換えることができます。

現在サポートされているアーティファクトのリストについては、Artifact クラスのリファレンス ドキュメントをご覧ください。すべてのアーティファクト タイプには、知っておくと便利な特定のプロパティがあります。

カーディナリティ

Artifact のカーディナリティは、FileSystemLocation インスタンスの数、またはアーティファクト タイプのファイルまたはディレクトリの数を表します。アーティファクトのカーディナリティに関する情報は、その親クラスをチェックすることで取得できます。1 つの FileSystemLocation を持つアーティファクトは Artifact.Single のサブクラスになり、複数の FileSystemLocation インスタンスを持つアーティファクトは Artifact.Multiple のサブクラスになります。

FileSystemLocation タイプ

Artifact がファイルまたはディレクトリを表しているかどうかは、パラメータ化された FileSystemLocation 型を調べることで確認できます。この型は、RegularFile または Directory のいずれかになります。

サポートされているオペレーション

すべての Artifact クラスは、次のいずれかのインターフェースを実装して、サポートする操作を示すことができます。

  • Transformable: Artifact を Task への入力として使用できるようにします。Task は、Artifact に対して任意の変換を実行し、新しいバージョンの Artifact を出力します。
  • Appendable: Artifact.Multiple のサブクラスであるアーティファクトにのみ適用されます。これは、Artifact を追加できることを意味します。つまり、カスタム Task は、この Artifact タイプの新しいインスタンスを作成し、既存のリストに追加できます。
  • Replaceable: Artifact.Single のサブクラスであるアーティファクトにのみ適用されます。置換可能な Artifact は、Task の出力として生成された、完全に新しいインスタンスに置き換えることができます。

3 つのアーティファクト変更オペレーションに加えて、すべてのアーティファクトは get()(または getAll())オペレーションをサポートしています。このオペレーションは、アーティファクトの最終バージョン(すべてのオペレーションが完了した後)を含む Provider を返します。

複数のプラグインが、onVariants() コールバックからアーティファクトに対する任意の数のオペレーションをパイプラインに追加できます。AGP は、それらが適切にチェーンされ、すべてのタスクが適切なタイミングで実行され、アーティファクトが正しく生成および更新されるようにします。つまり、オペレーションが出力を追加、置換、変換して変更すると、後続の各オペレーションは、これらのアーティファクトの更新されたバージョンを入力として認識します。

オペレーションを登録するためのエントリ ポイントは Artifacts クラスです。次のコード スニペットは、onVariants() コールバックで Variant オブジェクトのプロパティから Artifacts のインスタンスにアクセスする方法を示しています。

次に、カスタム TaskProvider を渡して TaskBasedOperation オブジェクトを取得し(1)、wiredWith* メソッドのいずれかを使用して、その入力と出力を接続します(2)。

選択する必要がある正確なメソッドは、変換する Artifact によって実装されるカーディナリティと FileSystemLocation タイプによって異なります。

最後に、Artifact タイプを、戻り値として取得する *OperationRequest オブジェクトで選択したオペレーションを表すメソッド(toAppendTo()、toTransform()、toCreate() など)に渡します(3)。

androidComponents.onVariants { variant ->
    val manifestUpdater = // Custom task that will be used for the transform.
            project.tasks.register(variant.name + "ManifestUpdater", ManifestTransformerTask::class.java) {
                it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
            }
    // (1) Register the TaskProvider w.
    val variant.artifacts.use(manifestUpdater)
         // (2) Connect the input and output files.
        .wiredWithFiles(
            ManifestTransformerTask::mergedManifest,
            ManifestTransformerTask::updatedManifest)
        // (3) Indicate the artifact and operation type.
        .toTransform(SingleArtifact.MERGED_MANIFEST)
}

この例では、MERGED_MANIFEST は SingleArtifact、すなわち RegularFile です。そのため、wiredWithFiles メソッドを使用する必要があります。このメソッドは、入力に 1 つの RegularFileProperty 参照を受け入れ、出力に 1 つの RegularFileProperty を受け入れます。TaskBasedOperation クラスには、Artifact のカーディナリティと FileSystemLocation の型の他の組み合わせに対応する wiredWith* メソッドが他にもあります。

AGP の拡張について詳しくは、Gradle ビルドシステムのマニュアルで次のセクションを読むことをおすすめします。