Das Android Gradle-Plug-in (AGP) ist das offizielle Build-System für Android-Anwendungen. Sie unterstützt die Kompilierung vieler verschiedener Arten von Quellen und deren Verknüpfung in einer App, die Sie auf einem physischen Android-Gerät oder in einem Emulator ausführen können.
AGP enthält Erweiterungspunkte für Plug-ins, um Build-Eingaben zu steuern und seine Funktionalität durch neue Schritte zu erweitern, die in Standard-Build-Aufgaben eingebunden werden können. In früheren Versionen von AGP waren offizielle APIs nicht klar von internen Implementierungen getrennt. Ab Version 7.0 bietet AGP eine Reihe offizieller, stabiler APIs, auf die Sie sich verlassen können.
AGP API-Lebenszyklus
AGP folgt dem Lebenszyklus von Gradle-Features, um den Status seiner APIs festzulegen:
- Intern: Nicht für die öffentliche Nutzung bestimmt
- Inkubation: Für die öffentliche Nutzung verfügbar, aber nicht endgültig. Das bedeutet, dass sie in der endgültigen Version möglicherweise nicht abwärtskompatibel sind.
- Öffentlich: Für die öffentliche Nutzung verfügbar und stabil
- Eingestellt: Wird nicht mehr unterstützt und durch neue APIs ersetzt
Einstellungsrichtlinie
AGP entwickelt sich weiter, da alte APIs eingestellt und durch neue, stabile APIs und eine neue anbieterspezifische Sprache (DSL) ersetzt werden. Diese Entwicklung wird mehrere AGP-Releases umfassen. Weitere Informationen finden Sie im Zeitplan für die Migration der AGP API/DSL.
Wenn AGP APIs eingestellt werden, sind sie bei dieser oder anderen Migration weiterhin in der aktuellen Hauptversion verfügbar, generieren aber Warnungen. Eingestellte APIs werden im nächsten Hauptrelease vollständig aus der AGP entfernt. Wird eine API beispielsweise in AGP 7.0 eingestellt, ist sie in dieser Version verfügbar und generiert Warnungen. Diese API ist in AGP 8.0 nicht mehr verfügbar.
Beispiele für neue APIs, die bei gängigen Build-Anpassungen verwendet werden, finden Sie in den Android Gradle-Plug-in-Rezepten. Sie enthalten Beispiele für gängige Build-Anpassungen. Weitere Informationen zu den neuen APIs finden Sie in unserer Referenzdokumentation.
Grundlagen von Gradle-Builds
Diese Anleitung behandelt nicht das gesamte Gradle-Build-System. Sie enthält jedoch die mindestens erforderlichen Konzepte für die Einbindung unserer APIs und Links zur Hauptdokumentation von Gradle für weitere Informationen.
Wir gehen davon aus, dass Sie die Grundlagen der Funktionsweise von Gradle kennen, einschließlich der Konfiguration von Projekten, der Bearbeitung von Build-Dateien, der Anwendung von Plug-ins und der Ausführung von Aufgaben. Weitere Informationen zu den Grundlagen von Gradle in Bezug auf AGP finden Sie unter Build konfigurieren. Allgemeine Informationen zum Anpassen von Gradle-Plug-ins finden Sie unter Benutzerdefinierte Gradle-Plug-ins entwickeln.
Glossar zu Lazy-Typen für Gradle
Gradle bietet eine Reihe von Typen, die sich „träge“ verhalten oder die Ausführung umfangreicher Berechnungen oder die Erstellung von Task
auf spätere Buildphasen verschieben. Diese Typen bilden die Grundlage vieler Gradle- und AGP-APIs. Die folgende Liste enthält die wichtigsten Gradle-Typen, die an der verzögerten Ausführung beteiligt sind, und ihre wichtigsten Methoden.
Provider<T>
- Liefert einen Wert vom Typ
T
(wobei "T" einen beliebigen Typ bedeutet), der während der Ausführungsphase mitget()
gelesen oder mit den Methodenmap()
,flatMap()
undzip()
in einen neuenProvider<S>
umgewandelt werden kann (wobei "S" für einen anderen Typ steht). Während der Konfigurationsphase sollteget()
niemals aufgerufen werden.map()
: Nimmt ein Lambda an und gibt eineProvider
vom TypS
,Provider<S>
zurück. Das Lambda-Argument fürmap()
nimmt den WertT
an und gibt den WertS
zurück. Die Lambda-Funktion wird nicht sofort ausgeführt. Stattdessen wird ihre Ausführung auf den Moment zurückgestellt, in demget()
für das resultierendeProvider<S>
aufgerufen wird, wodurch die gesamte Kette verzögert wird.flatMap()
: Akzeptiert auch eine Lambda-Funktion und gibtProvider<S>
zurück. Die Lambda-Funktion nimmt jedoch den WertT
an und gibtProvider<S>
zurück, anstatt direkt den WertS
zu erzeugen. Verwenden Sie flatMap(), wenn S bei der Konfiguration nicht ermittelt werden kann und Sie nurProvider<S>
erhalten können. Wenn Siemap()
verwendet und am Ende den ErgebnistypProvider<Provider<S>>
erhalten haben, bedeutet das wahrscheinlich, dass Sie stattdessenflatMap()
verwendet haben sollten.zip()
: Hiermit können Sie zweiProvider
-Instanzen kombinieren, um eine neueProvider
zu erstellen. Der Wert wird mit einer Funktion berechnet, die die Werte aus den beidenProviders
-Eingabeinstanzen kombiniert.
Property<T>
- implementiert
Provider<T>
und liefert daher auch einen Wert vom TypT
. Im Gegensatz zuProvider<T>
, das schreibgeschützt ist, können Sie auch einen Wert fürProperty<T>
festlegen. Dafür gibt es zwei Möglichkeiten:- Legen Sie einen Wert vom Typ
T
direkt fest, wenn er verfügbar ist, ohne dass verzögerte Berechnungen erforderlich sind. - Legen Sie eine weitere
Provider<T>
als Quelle für den Wert vonProperty<T>
fest. In diesem Fall wird der WertT
nur dann materialisiert, wennProperty.get()
aufgerufen wird.
- Legen Sie einen Wert vom Typ
TaskProvider
- Implementiert
Provider<Task>
. Verwenden Sie zum Generieren einesTaskProvider
tasks.register()
und nichttasks.create()
, damit Aufgaben nur verzögert instanziiert werden, wenn sie benötigt werden. MitflatMap()
können Sie auf die Ausgaben einerTask
zugreifen, bevor dieTask
erstellt wird. Dies kann nützlich sein, wenn Sie die Ausgaben als Eingaben für andereTask
-Instanzen verwenden möchten.
Anbieter und ihre Transformationsmethoden sind unerlässlich, um Eingaben und Ausgaben von Aufgaben auf lazy-Weise einzurichten, d. h., ohne dass alle Aufgaben vorab erstellt und die Werte aufgelöst werden müssen.
Anbieter enthalten auch Informationen zu Aufgabenabhängigkeiten. Wenn Sie eine Provider
durch Transformieren einer Task
-Ausgabe erstellen, wird diese Task
zu einer impliziten Abhängigkeit der Provider
. Sie wird erstellt und ausgeführt, wenn der Wert der Provider
aufgelöst wird, z. B. wenn sie für eine andere Task
erforderlich ist.
Hier ein Beispiel für die Registrierung von zwei Aufgaben, GitVersionTask
und ManifestProducerTask
, wobei die Erstellung der Task
-Instanzen bis zur tatsächlichen Notwendigkeit verschoben wird. Der Eingabewert für ManifestProducerTask
wird auf einen Provider
festgelegt, der aus der Ausgabe von GitVersionTask
stammt. ManifestProducerTask
hängt also implizit von GitVersionTask
ab.
// 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))
}
Diese beiden Aufgaben werden nur ausgeführt, wenn sie ausdrücklich angefordert werden. Dies kann im Rahmen eines Gradle-Aufrufs geschehen, z. B. wenn Sie ./gradlew
debugManifestProducer
ausführen oder wenn die Ausgabe von ManifestProducerTask
mit einer anderen Aufgabe verbunden ist und ihr Wert erforderlich wird.
Sie werden zwar benutzerdefinierte Aufgaben schreiben, die Eingaben verarbeiten und/oder Ausgaben erzeugen, aber AGP bietet keinen direkten öffentlichen Zugriff auf seine eigenen Aufgaben. Sie sind eine Implementierungsangelegenheit, die sich von Version zu Version ändern kann. Stattdessen bietet AGP die Variant API und Zugriff auf die Ausgabe der Aufgaben bzw. Build-Artefakte, die Sie lesen und transformieren können. Weitere Informationen finden Sie in diesem Dokument unter Variant API, Artifacts und Tasks.
Gradle-Build-Phasen
Das Erstellen eines Projekts ist von Natur aus ein komplexer und ressourcenintensiver Prozess. Es gibt verschiedene Funktionen wie die Vermeidung der Aufgabenkonfiguration, Aktualisierungsüberprüfungen und die Konfigurations-Caching-Funktion, mit denen sich die Zeit für reproduzierbare oder unnötige Berechnungen minimieren lässt.
Damit einige dieser Optimierungen angewendet werden können, müssen Gradle-Skripts und Plug-ins in jeder der verschiedenen Gradle-Build-Phasen strenge Regeln einhalten: Initialisierung, Konfiguration und Ausführung. In diesem Leitfaden konzentrieren wir uns auf die Konfigurations- und Ausführungsphase. Weitere Informationen zu allen Phasen finden Sie in der Gradle-Build-Lebenszyklusanleitung.
Konfigurationsphase
Während der Konfigurationsphase werden die Build-Skripts für alle zum Build gehörenden Projekte evaluiert, die Plug-ins angewendet und die Build-Abhängigkeiten aufgelöst. In dieser Phase sollten Sie den Build mit DSL-Objekten konfigurieren und Aufgaben und ihre Eingaben verzögert registrieren.
Da die Konfigurationsphase immer ausgeführt wird, unabhängig davon, welche Aufgabe ausgeführt werden soll, ist es besonders wichtig, sie schlank zu halten und alle Berechnungen darauf zu beschränken, dass sie nur von den Build-Scripts selbst abhängen.
Das heißt, Sie sollten keine externen Programme ausführen, keine Daten aus dem Netzwerk lesen und keine langen Berechnungen durchführen, die in die Ausführungsphase als ordnungsgemäße Task
-Instanzen verschoben werden können.
Ausführungsphase
In der Ausführungsphase werden die angeforderten Aufgaben und ihre abhängigen Aufgaben ausgeführt. Insbesondere werden die mit @TaskAction
gekennzeichneten Task
-Klassenmethoden ausgeführt. Während der Aufgabenausführung können Sie aus Eingaben lesen (z. B. aus Dateien) und durch Aufrufen von Provider<T>.get()
verzögerte Anbieter auflösen. Wenn Sie Lazy-Anbieter auf diese Weise auflösen, wird eine Abfolge von map()
- oder flatMap()
-Aufrufen gestartet, die den im Anbieter enthaltenen Informationen zu Aufgabenabhängigkeiten folgen. Aufgaben werden verzögert ausgeführt, um die erforderlichen Werte zu erfassen.
Variant API, Artefakte und Aufgaben
Die Variant API ist ein Erweiterungsmechanismus im Android Gradle-Plug-in, mit dem Sie die verschiedenen Optionen, die normalerweise mit der DSL in Build-Konfigurationsdateien festgelegt werden und sich auf den Android-Build auswirken, bearbeiten können. Die Variant API bietet Ihnen außerdem Zugriff auf Zwischen- und Endartefakte, die durch den Build erstellt werden, z. B. Klassendateien, das zusammengeführte Manifest oder APK-/AAB-Dateien.
Android-Build-Ablauf und Erweiterungspunkte
Verwenden Sie bei der Interaktion mit AGP speziell entwickelte Erweiterungspunkte, anstatt die typischen Gradle-Lebenszyklus-Callbacks (z. B. afterEvaluate()
) zu registrieren oder explizite Task
-Abhängigkeiten einzurichten. Von AGP erstellte Aufgaben gelten als Implementierungsdetails und werden nicht als öffentliche API bereitgestellt. Sie dürfen nicht versuchen, Instanzen der Task
-Objekte abzurufen oder die Task
-Namen zu erraten und diesen Task
-Objekten direkt Rückrufe oder Abhängigkeiten hinzuzufügen.
AGP führt die folgenden Schritte aus, um die Task
-Instanzen zu erstellen und auszuführen, die wiederum die Build-Artefakte erzeugen. Auf die wichtigsten Schritte beim Erstellen von Variant
-Objekten folgen Callbacks, mit denen Sie Änderungen an bestimmten Objekten vornehmen können, die im Rahmen eines Builds erstellt wurden. Beachten Sie, dass alle Callbacks während der Konfigurationsphase (wie auf dieser Seite beschrieben) stattfinden und schnell ausgeführt werden müssen. Komplizierte Arbeiten müssen in der Ausführungsphase auf die entsprechenden Task
-Instanzen verschoben werden.
- DSL-Parsing: Dabei werden Build-Scripts ausgewertet und die verschiedenen Eigenschaften der Android DSL-Objekte aus dem
android
-Block erstellt und festgelegt. In dieser Phase werden auch die in den folgenden Abschnitten beschriebenen Variant API-Callbacks registriert. finalizeDsl()
: Callback, mit dem Sie DSL-Objekte ändern können, bevor sie für die Erstellung von Komponenten (Varianten) gesperrt werden.VariantBuilder
-Objekte werden basierend auf Daten in den DSL-Objekten erstellt.DSL-Sperre: DSL ist jetzt gesperrt und Änderungen sind nicht mehr möglich.
beforeVariants()
: Über diesen Rückruf können Sie überVariantBuilder
beeinflussen, welche Komponenten erstellt werden und welche Eigenschaften sie haben. Es sind jedoch weiterhin Änderungen am Build-Vorgang und an den erstellten Artefakten möglich.Variantenerstellung: Die Liste der zu erstellenden Komponenten und Artefakte ist jetzt fertig und kann nicht mehr geändert werden.
onVariants()
: In diesem Callback erhalten Sie Zugriff auf die erstelltenVariant
-Objekte und können Werte oder Anbieter für die darin enthaltenenProperty
-Werte festlegen, die verzögert berechnet werden sollen.Gesperrte Varianten: Variantenobjekte sind jetzt gesperrt und Änderungen sind nicht mehr möglich.
Erstellte Aufgaben: Mit
Variant
-Objekten und ihrenProperty
-Werten werden dieTask
-Instanzen erstellt, die für die Ausführung des Builds erforderlich sind.
AGP führt die AndroidComponentsExtension
ein, mit der du Callbacks für finalizeDsl()
, beforeVariants()
und onVariants()
registrieren kannst.
Die Erweiterung ist in Build-Scripts über den Block androidComponents
verfügbar:
// This is used only for configuring the Android build through DSL.
android { ... }
// The androidComponents block is separate from the DSL.
androidComponents {
finalizeDsl { extension ->
...
}
}
Wir empfehlen jedoch, Build-Scripts nur für die deklarative Konfiguration mit der DSL des Android-Blocks zu verwenden und benutzerdefinierte imperative Logik in buildSrc
oder externe Plug-ins zu verschieben. In den buildSrc
-Beispielen im GitHub-Repository für Gradle-Rezepte erfahren Sie, wie Sie ein Plug-in in Ihrem Projekt erstellen. Hier ist ein Beispiel für die Registrierung der Callbacks vom Plug-in-Code:
abstract class ExamplePlugin: Plugin<Project> {
override fun apply(project: Project) {
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.finalizeDsl { extension ->
...
}
}
}
Sehen wir uns die verfügbaren Callbacks und die Anwendungsfälle an, die dein Plug-in in jedem Fall unterstützen kann:
finalizeDsl(callback: (DslExtensionT) -> Unit)
In diesem Callback können Sie auf die erstellten DSL-Objekte zugreifen und diese ändern. Dazu parsen Sie die Informationen aus dem Block android
in den Build-Dateien.
Diese DSL-Objekte werden zum Initialisieren und Konfigurieren von Varianten in späteren Build-Phasen verwendet. Sie können beispielsweise programmatisch neue Konfigurationen erstellen oder Attribute überschreiben. Beachten Sie jedoch, dass alle Werte zum Zeitpunkt der Konfiguration aufgelöst werden müssen, sodass sie nicht auf externen Eingaben basieren dürfen.
Nach Abschluss der Ausführung dieses Callbacks sind die DSL-Objekte nicht mehr nützlich. Sie sollten keine Verweise mehr darauf speichern oder ihre Werte ändern.
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()
In dieser Build-Phase erhalten Sie Zugriff auf VariantBuilder
-Objekte, die die zu erstellenden Varianten und ihre Eigenschaften bestimmen. So können Sie beispielsweise bestimmte Varianten und ihre Tests programmatisch deaktivieren oder den Wert einer Property (z. B. minSdk
) nur für eine ausgewählte Variante ändern. Ähnlich wie bei finalizeDsl()
müssen alle von Ihnen angegebenen Werte bei der Konfiguration aufgelöst werden und dürfen nicht von externen Eingaben abhängen. Die VariantBuilder
-Objekte dürfen nach Abschluss der Ausführung des beforeVariants()
-Callbacks nicht mehr geändert werden.
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
Der beforeVariants()
-Callback kann optional eine VariantSelector
annehmen, die du über die Methode selector()
der androidComponentsExtension
abrufen kannst. Sie können damit Komponenten, die am Callback-Aufruf beteiligt sind, nach ihrem Namen, Build-Typ oder Produkt-Flavor filtern.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
Zum Zeitpunkt des Aufrufs von onVariants()
sind alle Artefakte, die von AGP erstellt werden, bereits festgelegt, sodass Sie sie nicht mehr deaktivieren können. Sie können jedoch einige der für die Aufgaben verwendeten Werte ändern, indem Sie sie für Property
-Attribute in den Variant
-Objekten festlegen. Da die Property
-Werte nur aufgelöst werden, wenn die Aufgaben von AGP ausgeführt werden, können Sie sie sicher von Ihren eigenen benutzerdefinierten Aufgaben an Anbieter weiterleiten, die alle erforderlichen Berechnungen ausführen, einschließlich des Lesens aus externen Eingaben wie Dateien oder dem Netzwerk.
// 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() })
}
Generierte Quellen zum Build beitragen
Das Plug-in kann verschiedene Arten generierter Quellen bereitstellen, z. B.:
- Anwendungscode im Verzeichnis
java
- Android-Ressourcen im Verzeichnis
res
- Java-Ressourcen im Verzeichnis
resources
- Android-Assets im Verzeichnis
assets
Eine vollständige Liste der Quellen, die Sie hinzufügen können, finden Sie in der Sources API.
In diesem Code-Snippet wird gezeigt, wie Sie dem Java-Quellsatz mithilfe der Funktion addStaticSourceDirectory()
einen benutzerdefinierten Quellordner namens ${variant.name}
hinzufügen. Die Android-Toolchain verarbeitet dann diesen Ordner.
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
Weitere Informationen finden Sie im Rezept addJavaSource.
In diesem Code-Snippet wird gezeigt, wie Sie dem res
-Quellsatz ein Verzeichnis mit Android-Ressourcen hinzufügen, das aus einer benutzerdefinierten Aufgabe generiert wurde. Der Vorgang ist für andere Quelltypen ähnlich.
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.
...
}
}
Weitere Informationen finden Sie im Schema "addCustomAsset".
Artefakte aufrufen und bearbeiten
Sie können mit AGP nicht nur einfache Attribute der Variant
-Objekte ändern, sondern auch einen Erweiterungsmechanismus, mit dem Sie während des Build erstellte Zwischen- und Endartefakte lesen oder transformieren können. Sie können beispielsweise den endgültigen, zusammengeführten Inhalt der Datei AndroidManifest.xml
in einer benutzerdefinierten Task
lesen, um ihn zu analysieren, oder den Inhalt vollständig durch den Inhalt einer Manifestdatei ersetzen, die von Ihrem benutzerdefinierten Task
generiert wurde.
Eine Liste der derzeit unterstützten Artefakte finden Sie in der Referenzdokumentation zur Klasse Artifact
. Jeder Artefakttyp hat bestimmte Attribute, die Sie kennen sollten:
Kardinalität
Die Kardinalität eines Artifact
entspricht der Anzahl der FileSystemLocation
-Instanzen oder der Anzahl der Dateien oder Verzeichnisse des Artefakttyps. Informationen zur Kardinalität eines Artefakts finden Sie in der übergeordneten Klasse: Artefakte mit einer einzelnen FileSystemLocation
sind eine Unterklasse von Artifact.Single
; Artefakte mit mehreren FileSystemLocation
-Instanzen sind eine Unterklasse von Artifact.Multiple
.
FileSystemLocation
Typ
Sie können prüfen, ob eine Artifact
Dateien oder Verzeichnisse darstellt, indem Sie sich den parametrisierten FileSystemLocation
-Typ ansehen, der entweder RegularFile
oder Directory
sein kann.
Unterstützte Vorgänge
Jede Artifact
-Klasse kann eine der folgenden Schnittstellen implementieren, um anzugeben, welche Vorgänge sie unterstützen:
Transformable
: Ermöglicht die Verwendung einesArtifact
als Eingabe für eineTask
, die beliebige Transformationen darauf durchführt und eine neue Version vonArtifact
ausgibt.Appendable
: Gilt nur für Artefakte, die Unterklassen vonArtifact.Multiple
sind. Das bedeutet, dass demArtifact
etwas angehängt werden kann, d. h., mit einem benutzerdefiniertenTask
können neue Instanzen diesesArtifact
-Typs erstellt werden, die der vorhandenen Liste hinzugefügt werden.Replaceable
: Gilt nur für Artefakte, die Unterklassen vonArtifact.Single
sind. Eine austauschbareArtifact
kann durch eine völlig neue Instanz ersetzt werden, die als Ausgabe einerTask
generiert wird.
Zusätzlich zu den drei Artefaktbearbeitungsvorgängen unterstützt jedes Artefakt einen get()
- oder getAll()
-Vorgang, der einen Provider
mit der endgültigen Version des Artefakts zurückgibt (nachdem alle Vorgänge für das Artefakt abgeschlossen sind).
Mehrere Plug-ins können der Pipeline eine beliebige Anzahl von Vorgängen für Artefakte aus dem onVariants()
-Callback hinzufügen. AGP sorgt dafür, dass sie ordnungsgemäß verkettet sind, sodass alle Aufgaben zur richtigen Zeit ausgeführt und Artefakte korrekt erstellt und aktualisiert werden. Das bedeutet, dass bei einem Vorgang, bei dem Ausgaben durch Anhängen, Ersetzen oder Transformieren geändert werden, die aktualisierte Version dieser Artefakte als Eingaben für den nächsten Vorgang verwendet wird usw.
Der Einstiegspunkt für die Registrierung von Vorgängen ist die Klasse Artifacts
.
Im folgenden Code-Snippet wird gezeigt, wie du im onVariants()
-Callback über eine Eigenschaft des Variant
-Objekts auf eine Instanz von Artifacts
zugreifen kannst.
Sie können dann Ihre benutzerdefinierte TaskProvider
übergeben, um ein TaskBasedOperation
-Objekt (1) zu erhalten, und damit die Eingaben und Ausgaben mit einer der wiredWith*
-Methoden (2) verbinden.
Welche Methode Sie auswählen müssen, hängt von der Kardinalität und dem FileSystemLocation
-Typ ab, der von der Artifact
implementiert wird, die Sie transformieren möchten.
Schließlich übergeben Sie den Artifact
-Typ an eine Methode, die den ausgewählten Vorgang auf dem zurückgegebenen *OperationRequest
-Objekt darstellt, z. B. toAppendTo()
, toTransform()
oder 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)
}
In diesem Beispiel ist MERGED_MANIFEST
ein SingleArtifact
und ein RegularFile
. Daher müssen wir die Methode wiredWithFiles
verwenden, die eine einzelne RegularFileProperty
-Referenz für die Eingabe und eine einzelne RegularFileProperty
für die Ausgabe akzeptiert. Es gibt weitere wiredWith*
-Methoden für die Klasse TaskBasedOperation
, die mit anderen Kombinationen aus Artifact
-Kardinalität und FileSystemLocation
-Typen funktionieren.
Weitere Informationen zum Erweitern von AGP finden Sie in den folgenden Abschnitten des Handbuchs zum Gradle-Buildsystem:
- Benutzerdefinierte Gradle-Plug-ins entwickeln
- Gradle-Plug-ins implementieren
- Benutzerdefinierte Gradle-Aufgabentypen entwickeln
- Verzögerte Konfiguration
- Vermeidung von Aufgabenkonfigurationen