Das Android Gradle-Plug-in (AGP) ist das offizielle Build-System für Android-Anwendungen. Sie umfasst auch die Möglichkeit, viele verschiedene Arten von Quellen zu kompilieren und sie zu einer Anwendung zu verknüpfen, die Sie auf einem physischen Android-Gerät oder in einem Emulator ausführen können.
AGP enthält Erweiterungspunkte für Plug-ins, mit denen Build-Eingaben gesteuert und ihre Funktionalität durch neue Schritte erweitert werden können, 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 Gradle-Funktionslebenszyklus, um den Status seiner APIs festzulegen:
- Intern: Nicht für die öffentliche Verwendung bestimmt
- Inkubieren: Verfügbar für die öffentliche Verwendung, aber nicht endgültig, was bedeutet, dass sie in der endgültigen Version möglicherweise nicht abwärtskompatibel sind.
- Öffentlich: Für die öffentliche Verwendung verfügbar und stabil
- Eingestellt: Wird nicht mehr unterstützt und durch neue APIs ersetzt.
Richtlinie zur Einstellung von Produkten und Diensten
AGP entwickelt sich weiter, da alte APIs eingestellt und durch neue, stabile APIs und eine neue domainspezifische Sprache (DSL) ersetzt werden. Diese Entwicklung umfasst mehrere AGP-Releases. Weitere Informationen dazu können Sie dem Zeitplan für die AGP API/DSL-Migration entnehmen.
Wenn AGP APIs verworfen werden, ob entweder für diese Migration oder anderweitig, sind sie weiterhin im aktuellen Hauptrelease verfügbar, es werden jedoch Warnungen generiert. Verworfene APIs werden in der nachfolgenden Hauptversion vollständig aus AGP entfernt. Wenn eine API beispielsweise in AGP 7.0 verworfen wird, ist sie in dieser Version verfügbar und es werden Warnungen ausgegeben. Diese API ist in AGP 8.0 nicht mehr verfügbar.
Beispiele für neue APIs, die in gängigen Build-Anpassungen verwendet werden, finden Sie in den Rezepten für Android-Gradle-Plug-ins. Sie enthalten Beispiele für gängige Build-Anpassungen. Weitere Informationen zu den neuen APIs finden Sie in unserer Referenzdokumentation.
Gradle-Build-Grundlagen
Diese Anleitung deckt nicht das gesamte Gradle-Build-System ab. Er deckt jedoch die mindestens erforderlichen Konzepte für die Integration unserer APIs ab und enthält Links zur Gradle-Hauptdokumentation mit weiteren Informationen.
Es wird vorausgesetzt, dass Sie Grundkenntnisse zur Funktionsweise von Gradle haben, z. B. wie Projekte konfiguriert, Build-Dateien bearbeitet, Plug-ins angewendet und Aufgaben ausgeführt werden. Weitere Informationen zu den Grundlagen von Gradle in Bezug auf AGP finden Sie unter Build konfigurieren. Informationen zum allgemeinen Framework zum Anpassen von Gradle-Plug-ins finden Sie unter Benutzerdefinierte Gradle-Plug-ins entwickeln.
Glossar für Lazy-Typen für Gradle
Gradle bietet eine Reihe von Typen, die sich „verzögert“ verhalten. Sie können dazu beitragen, schwere Berechnungen oder die Task
-Erstellung auf spätere Phasen des Builds zu verschieben. Diese Typen bilden den Kern vieler Gradle- und AGP-APIs. Die folgende Liste enthält die wichtigsten Gradle-Typen der Lazy Execution und ihre Schlüsselmethoden.
Provider<T>
- Liefert einen Wert vom Typ
T
(wobei „T“ für einen beliebigen Typ steht), der während der Ausführungsphase mitget()
gelesen oder in einen neuenProvider<S>
umgewandelt werden kann (wobei „S“ für einen anderen Typ steht) mit den Methodenmap()
,flatMap()
undzip()
. Während der Konfigurationsphase sollteget()
auf keinen Fall aufgerufen werden.map()
: Akzeptiert ein Lambda und erzeugt einenProvider
vom TypS
,Provider<S>
. Das Lambda-Argument fürmap()
verwendet den WertT
und erzeugt den WertS
. Das Lambda wird nicht sofort ausgeführt, sondern erst in dem Moment, in demget()
für das resultierendeProvider<S>
aufgerufen wird, wodurch die gesamte Kette verzögert wird.flatMap()
: Akzeptiert ebenfalls ein Lambda und erzeugtProvider<S>
. Das Lambda nimmt jedoch den WertT
an und erzeugtProvider<S>
(anstatt den WertS
direkt zu erzeugen). Verwenden Sie „flatMap()“, wenn S bei der Konfiguration nicht ermittelt werden kann und Sie nurProvider<S>
erhalten. Wenn Siemap()
verwendet haben und schließlich den ErgebnistypProvider<Provider<S>>
erhalten, bedeutet dies wahrscheinlich, dass Sie stattdessenflatMap()
verwenden sollten.zip()
: Ermöglicht die Kombination von zweiProvider
-Instanzen, um eine neueProvider
zu erstellen, mit einem Wert, der mithilfe einer Funktion berechnet wird, die die Werte der beidenProviders
-Eingabeinstanzen kombiniert.
Property<T>
- Implementiert
Provider<T>
und liefert daher auch einen Wert vom TypT
. Im Gegensatz zum schreibgeschütztenProvider<T>
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 des Werts vonProperty<T>
fest. In diesem Fall wird der WertT
nur 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 bei Bedarf verzögert instanziiert 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 verzögerte Art und Weise einzurichten, d. h., ohne dass alle Aufgaben im Voraus erstellt und die Werte aufgelöst werden müssen.
Anbieter haben auch Informationen zu Aufgabenabhängigkeiten. Wenn Sie eine Provider
durch Transformieren einer Task
-Ausgabe erstellen, wird diese Task
zu einer impliziten Abhängigkeit von Provider
und wird erstellt und ausgeführt, wenn der Wert von Provider
aufgelöst wird, z. B. wenn eine andere Task
dies erfordert.
Hier ist ein Beispiel für die Registrierung der beiden Aufgaben GitVersionTask
und ManifestProducerTask
, während die Erstellung der Task
-Instanzen aufgeschoben wird, bis sie tatsächlich benötigt werden. Der Eingabewert ManifestProducerTask
wird auf einen Provider
festgelegt, der aus der Ausgabe von GitVersionTask
abgerufen wird, sodass ManifestProducerTask
implizit von GitVersionTask
abhängt.
// 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 explizit 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 deren Wert erforderlich wird.
Sie schreiben zwar benutzerdefinierte Aufgaben, die Eingaben verarbeiten und/oder Ausgaben erzeugen, aber AGP bietet keinen direkten öffentlichen Zugriff auf seine eigenen Aufgaben. Sie sind ein Implementierungsdetail, das sich von Version zu Version ändern kann. Stattdessen bietet AGP die Variant API und Zugriff auf die Ausgabe der zugehörigen Aufgaben bzw. Build-Artefakte, die Sie lesen und transformieren können. Weitere Informationen finden Sie in diesem Dokument unter Variante API, Artefakte und Tasks.
Gradle-Build-Phasen
Das Erstellen eines Projekts ist grundsätzlich ein komplizierter und ressourcenintensiver Prozess. Es gibt verschiedene Funktionen wie die Vermeidung von Aufgabenkonfigurationen, aktuelle Prüfungen und das Konfigurations-Caching-Feature, die dazu beitragen, den Zeitaufwand für reproduzierbare oder unnötige Berechnungen zu minimieren.
Damit einige dieser Optimierungen angewendet werden können, müssen Gradle-Skripts und -Plug-ins in jeder der 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 Anleitung zum Gradle-Build-Lebenszyklus.
Konfigurationsphase
Während der Konfigurationsphase werden die Build-Skripts für alle Projekte, die Teil des Builds sind, ausgewertet, die Plug-ins angewendet und Build-Abhängigkeiten aufgelöst. Diese Phase sollte verwendet werden, um den Build mit DSL-Objekten zu konfigurieren und Aufgaben und deren Eingaben verzögert zu registrieren.
Da die Konfigurationsphase immer ausgeführt wird, unabhängig davon, welche Aufgabe angefordert wird, ist es besonders wichtig, sie schlank zu halten und alle Berechnungen von anderen Eingaben als den Build-Skripts selbst einzuschränken.
Das heißt, Sie sollten keine externen Programme ausführen, aus dem Netzwerk lesen oder lange Berechnungen durchführen, die als richtige Task
-Instanzen in die Ausführungsphase 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 Klassenmethoden Task
ausgeführt. Während der Aufgabenausführung können Sie aus Eingaben (z. B. Dateien) lesen und lazy Providers auflösen, indem Sie Provider<T>.get()
aufrufen. Wenn Sie lazy Provider auf diese Weise auflösen, wird eine Sequenz 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 Tasks
Die Variant API ist ein Erweiterungsmechanismus im Android-Gradle-Plug-in, mit dem Sie die verschiedenen Optionen bearbeiten können. Sie werden normalerweise mit dem DSL in Build-Konfigurationsdateien festgelegt und beeinflussen den Android-Build. Die Variant API bietet auch 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 spezielle 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. Versuchen Sie nicht, Instanzen der Task
-Objekte abzurufen, die Task
-Namen zu erraten und Callbacks oder Abhängigkeiten direkt zu diesen Task
-Objekten hinzuzufügen.
AGP führt die folgenden Schritte aus, um seine Task
-Instanzen zu erstellen und auszuführen, die wiederum die Build-Artefakte erzeugen. Auf die Hauptschritte zum Erstellen eines Variant
-Objekts folgen Callbacks, mit denen Sie Änderungen an bestimmten Objekten vornehmen können, die im Rahmen eines Builds erstellt wurden. Wichtig: Alle Callbacks erfolgen während der Konfigurationsphase (siehe Beschreibung auf dieser Seite) und müssen schnell ausgeführt werden, wobei jede komplizierte Arbeit an ordnungsgemäße Task
-Instanzen während der Ausführungsphase aufgeschoben werden muss.
- DSL-Parsing: Hierbei werden Build-Skripts ausgewertet und die verschiedenen Attribute der Android-DSL-Objekte aus dem
android
-Block erstellt und festgelegt. Die in den folgenden Abschnitten beschriebenen Variant API-Callbacks werden in dieser Phase ebenfalls registriert. finalizeDsl()
: Callback, mit dem Sie DSL-Objekte ändern können, bevor sie für das Erstellen von Komponenten (Varianten) gesperrt werden.VariantBuilder
-Objekte werden basierend auf Daten erstellt, die in den DSL-Objekten enthalten sind.DSL-Sperre: DSL ist jetzt gesperrt und Änderungen sind nicht mehr möglich.
beforeVariants()
: Dieser Callback kann beeinflussen, welche Komponenten und einige ihrer Eigenschaften überVariantBuilder
erstellt werden. Es ermöglicht weiterhin Änderungen am Build-Ablauf und an den generierten Artefakten.Erstellung von Varianten: Die Liste der Komponenten und Artefakte, die erstellt werden, ist jetzt final 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.Variantensperrung: Variantenobjekte sind jetzt gesperrt und Änderungen sind nicht mehr möglich.
Erstellte Aufgaben:
Variant
-Objekte und ihreProperty
-Werte werden zum Erstellen derTask
-Instanzen verwendet, die zum Ausführen des Builds erforderlich sind.
AGP führt einen AndroidComponentsExtension
ein, mit dem Sie Callbacks für finalizeDsl()
, beforeVariants()
und onVariants()
registrieren können.
Die Erweiterung ist in Build-Skripts über den androidComponents
-Block 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-Skripts nur für die deklarative Konfiguration mithilfe der DSL des Android-Blocks beizubehalten und benutzerdefinierte imperative Logik auf buildSrc
oder externe Plug-ins zu verschieben. In den buildSrc
-Beispielen im GitHub-Repository für Gradle-Rezepte erfahren Sie, wie Sie Plug-ins in Ihrem Projekt erstellen. Hier ist ein Beispiel für das Registrieren der Callbacks aus dem 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 Art der Anwendungsfälle genauer an, die das Plug-in jeweils unterstützen kann:
finalizeDsl(callback: (DslExtensionT) -> Unit)
In diesem Callback können Sie auf die erstellten DSL-Objekte zugreifen und diese ändern, indem Sie die Informationen aus dem android
-Block in den Build-Dateien parsen.
Diese DSL-Objekte werden in späteren Phasen des Builds zum Initialisieren und Konfigurieren von Varianten 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 und nicht auf externen Eingaben basieren dürfen.
Nachdem dieser Callback ausgeführt wurde, sind die DSL-Objekte nicht mehr nützlich. Sie sollten keine Verweise mehr auf sie haben und ihre Werte nicht mehr ä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 lassen sich beispielsweise programmatisch bestimmte Varianten und deren Tests deaktivieren oder der Wert einer Eigenschaft (z. B. minSdk
) nur für eine ausgewählte Variante ändern. Ähnlich wie bei finalizeDsl()
müssen alle angegebenen Werte zum Zeitpunkt der Konfiguration aufgelöst werden und sind nicht von externen Eingaben abhängig. Die VariantBuilder
-Objekte dürfen nicht mehr geändert werden, nachdem die Ausführung des beforeVariants()
-Callbacks abgeschlossen ist.
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
Für den Callback beforeVariants()
wird optional ein VariantSelector
verwendet, das Sie über die Methode selector()
im androidComponentsExtension
abrufen können. Damit können Sie die am Callback-Aufruf beteiligten Komponenten nach ihrem Namen, Build-Typ oder Produktsortiment filtern.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
Zum Zeitpunkt des Aufrufs von onVariants()
sind alle von AGP erstellten Artefakte bereits festgelegt, sodass sie nicht mehr deaktiviert werden können. Einige der für die Aufgaben verwendeten Werte können Sie jedoch ä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 durchfü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
Ihr Plug-in kann verschiedene Typen 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 unter Sources API.
Dieses Code-Snippet zeigt, wie Sie mit der Funktion addStaticSourceDirectory()
dem Java-Quellsatz einen benutzerdefinierten Quellordner mit dem Namen ${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 addJavaSource-Rezept.
Dieses Code-Snippet zeigt, wie Sie dem Quellsatz res
ein Verzeichnis mit Android-Ressourcen hinzufügen, die aus einer benutzerdefinierten Aufgabe generiert wurden. Der Prozess 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 Rezept für addCustomAsset.
Auf Artefakte zugreifen und diese ändern
AGP bietet nicht nur die Möglichkeit, einfache Eigenschaften der Variant
-Objekte zu ändern, sondern enthält auch einen Erweiterungsmechanismus, mit dem Sie Zwischen- und endgültige Artefakte lesen oder transformieren können, die während des Builds erstellt wurden. Beispielsweise können Sie den endgültigen, zusammengeführten AndroidManifest.xml
-Dateiinhalt in einer benutzerdefinierten Task
lesen, um ihn zu analysieren, oder Sie können den Inhalt vollständig durch den Inhalt einer Manifestdatei ersetzen, die von Ihrer benutzerdefinierten Task
generiert wurde.
Eine Liste der derzeit unterstützten Artefakte finden Sie in der Referenzdokumentation für die 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 erhalten Sie durch Prüfen der übergeordneten Klasse: Artefakte mit einer einzelnen FileSystemLocation
sind eine abgeleitete Klasse von Artifact.Single
. Artefakte mit mehreren FileSystemLocation
-Instanzen sind eine abgeleitete Klasse von Artifact.Multiple
.
FileSystemLocation
Typ
Sie können prüfen, ob ein Artifact
Dateien oder Verzeichnisse darstellt. Sehen Sie sich dazu seinen parametrierten FileSystemLocation
-Typ an, 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 unterstützt werden:
Transformable
: Ermöglicht die Verwendung einesArtifact
als Eingabe für einTask
, das beliebige Transformationen ausführt und eine neue Version vonArtifact
ausgibt.Appendable
: Gilt nur für Artefakte, die abgeleitete Klassen vonArtifact.Multiple
sind. Das bedeutet, dassArtifact
an eine benutzerdefinierteTask
angehängt werden kann, sodass neue Instanzen diesesArtifact
-Typs erstellt und der vorhandenen Liste hinzugefügt werden können.Replaceable
: Gilt nur für Artefakte, die abgeleitete Klassen vonArtifact.Single
sind. Ein austauschbaresArtifact
kann durch eine völlig neue Instanz ersetzt werden, die als Ausgabe einesTask
erzeugt wird.
Zusätzlich zu den drei Artefaktänderungsvorgä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 dafür abgeschlossen sind).
Mehrere Plug-ins können eine beliebige Anzahl von Vorgängen für Artefakte aus dem onVariants()
-Callback in die Pipeline aufnehmen. AGP sorgt dann dafür, dass sie ordnungsgemäß verkettet werden, sodass alle Aufgaben zur richtigen Zeit ausgeführt werden und Artefakte korrekt erstellt und aktualisiert werden. Wenn also ein Vorgang die Ausgaben durch Anfügen, Ersetzen oder Transformieren ändert, sieht der nächste Vorgang die aktualisierte Version dieser Artefakte als Eingaben usw.
Der Einstiegspunkt für die Registrierung von Vorgängen ist die Klasse Artifacts
.
Das folgende Code-Snippet zeigt, wie Sie über eine Eigenschaft des Variant
-Objekts im onVariants()
-Callback Zugriff auf eine Instanz von Artifacts
erhalten.
Sie können dann Ihre benutzerdefinierte TaskProvider
übergeben, um ein TaskBasedOperation
-Objekt (1) zu erhalten und es verwenden, um die Ein- und Ausgaben mit einer der wiredWith*
-Methoden (2) zu verbinden.
Die genaue Methode, die Sie auswählen müssen, hängt von der Kardinalität und dem FileSystemLocation
-Typ ab, der von der Artifact
implementiert wurde, die Sie umwandeln möchten.
Außerdem übergeben Sie den Typ Artifact
an eine Methode, die den ausgewählten Vorgang für das *OperationRequest
-Objekt darstellt, das Sie erhalten, 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
. Aus diesem Grund 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. Für die Klasse TaskBasedOperation
gibt es andere wiredWith*
-Methoden, die auch für andere Kombinationen von Artifact
-Kardinalität und FileSystemLocation
-Typen geeignet sind.
Weitere Informationen zum Erweitern von AGP finden Sie in den folgenden Abschnitten des Gradle-Build-Systemhandbuchs:
- Benutzerdefinierte Gradle-Plug-ins entwickeln
- Gradle-Plug-ins implementieren
- Benutzerdefinierte Gradle-Aufgabentypen entwickeln
- Verzögerte Konfiguration
- Vermeiden von Aufgabenkonfigurationen