Das Android-Gradle-Plug-in (AGP) ist das offizielle Build-System für Android-Anwendungen. Es bietet Unterstützung für das Kompilieren vieler verschiedener Quellentypen und das Verknüpfen dieser Quellen zu einer Anwendung, die Sie auf einem physischen Android-Gerät oder einem Emulator ausführen können.
AGP enthält Erweiterungspunkte für Plug-ins, mit denen Build-Eingaben gesteuert und die Funktionalität durch neue Schritte erweitert werden kann, die in Standard-Build-Aufgaben integriert 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 von offiziellen, stabilen APIs, auf die Sie sich verlassen können.
AGP-API-Lebenszyklus
AGP folgt dem Gradle-Funktionslebenszyklus, um den Status seiner APIs anzugeben:
- Intern: Nicht für die öffentliche Nutzung vorgesehen
- In der Entwicklung: Öffentlich verfügbar, aber noch nicht final. 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
- Nicht mehr verfügbar: Wird nicht mehr unterstützt und durch neue APIs ersetzt
Einstellungsrichtlinie
AGP wird weiterentwickelt. Alte APIs werden eingestellt und durch neue, stabile APIs und eine neue domänenspezifische Sprache (DSL) ersetzt. Diese Entwicklung wird sich über mehrere AGP-Releases erstrecken. Weitere Informationen dazu finden Sie im AGP API/DSL-Migrationszeitplan.
Wenn AGP-APIs im Rahmen dieser Migration oder aus anderen Gründen eingestellt werden, sind sie weiterhin in der aktuellen Hauptversion verfügbar, es werden jedoch Warnungen generiert. Verworfene APIs werden im nachfolgenden Hauptrelease vollständig aus AGP entfernt. Wenn eine API beispielsweise in AGP 7.0 eingestellt wird, ist sie in dieser Version verfügbar und es werden Warnungen generiert. 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 Android Gradle-Plug-in-Rezepten. Sie enthalten Beispiele für gängige Anpassungen von Builds. Weitere Informationen zu den neuen APIs finden Sie in unserer Referenzdokumentation.
Grundlagen von Gradle-Builds
In diesem Leitfaden wird nicht das gesamte Gradle-Build-System behandelt. Es werden jedoch die mindestens erforderlichen Konzepte behandelt, die Sie für die Integration in unsere APIs benötigen. Außerdem finden Sie dort Links zur Hauptdokumentation von Gradle, in der Sie weitere Informationen finden.
Wir setzen grundlegende Kenntnisse der Funktionsweise von Gradle voraus, einschließlich der Konfiguration von Projekten, der Bearbeitung von Build-Dateien, der Anwendung von Plug-ins und der Ausführung von Aufgaben. Informationen zu den Grundlagen von Gradle in Bezug auf das AGP finden Sie unter Build konfigurieren. Informationen zum allgemeinen Framework für die Anpassung von Gradle-Plug-ins finden Sie unter Benutzerdefinierte Gradle-Plug-ins entwickeln.
Glossar zu Lazy-Typen in Gradle
Gradle bietet eine Reihe von Typen, die sich „lazy“ verhalten oder dazu beitragen, rechenintensive Berechnungen oder die Erstellung von Task
auf spätere Phasen des Builds zu verschieben. Diese Typen sind das Herzstück vieler Gradle- und AGP-APIs. Die folgende Liste enthält die wichtigsten Gradle-Typen, die an der verzögerten Ausführung beteiligt sind, sowie ihre wichtigsten Methoden.
Provider<T>
- Stellt einen Wert vom Typ
T
bereit (wobei „T“ für einen beliebigen Typ steht), der während der Ausführungsphase mitget()
gelesen oder mit den Methodenmap()
,flatMap()
undzip()
in einen neuenProvider<S>
(wobei „S“ für einen anderen Typ steht) transformiert werden kann. Beachten Sie, dassget()
niemals während der Konfigurationsphase aufgerufen werden sollte.map()
: Akzeptiert ein Lambda und gibt einProvider
vom TypS
,Provider<S>
zurück. Das Lambda-Argument fürmap()
hat den WertT
und ergibt den WertS
. Die Lambda-Funktion wird nicht sofort ausgeführt, sondern ihre Ausführung wird auf den Moment verschoben, in demget()
für das resultierendeProvider<S>
aufgerufen wird. Dadurch wird die gesamte Kette verzögert.flatMap()
: Akzeptiert auch einen Lambda-Ausdruck und gibtProvider<S>
zurück. Der Lambda-Ausdruck verwendet jedoch den WertT
und gibtProvider<S>
zurück (anstatt den WertS
direkt zurückzugeben). Verwenden Sie flatMap(), wenn S nicht zur Konfigurationszeit bestimmt werden kann und Sie nurProvider<S>
abrufen können. Wenn Siemap()
verwendet haben und der ErgebnistypProvider<Provider<S>>
ist, sollten Sie wahrscheinlich stattdessenflatMap()
verwenden.zip()
: Hiermit können Sie zweiProvider
-Instanzen kombinieren, um eine neueProvider
-Instanz zu erstellen. Der Wert wird mithilfe einer Funktion berechnet, die die Werte der beidenProviders
-Eingabeinstanzen kombiniert.
Property<T>
- Implementiert
Provider<T>
und stellt daher auch einen Wert vom TypT
bereit. 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:- Legt einen Wert vom Typ
T
direkt fest, wenn er verfügbar ist, ohne dass verzögerte Berechnungen erforderlich sind. - Legen Sie ein anderes
Provider<T>
als Quelle für den Wert vonProperty<T>
fest. In diesem Fall wird der WertT
nur materialisiert, wennProperty.get()
aufgerufen wird.
- Legt 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 einesTask
zugreifen, bevor dasTask
erstellt wird. Das 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 Ein- und Ausgaben von Aufgaben auf verzögerte Weise einzurichten, d. h. ohne dass alle Aufgaben vorab erstellt und die Werte aufgelöst werden müssen.
Provider enthalten auch Informationen zur Aufgabenabhängigkeit. Wenn Sie ein Provider
erstellen, indem Sie die Ausgabe eines Task
transformieren, wird dieses Task
zu einer impliziten Abhängigkeit des Provider
. Es wird erstellt und ausgeführt, wenn der Wert des Provider
aufgelöst wird, z. B. wenn ein anderes Task
es benötigt.
Hier ist ein Beispiel für die Registrierung von zwei Aufgaben, GitVersionTask
und ManifestProducerTask
, während die Erstellung der Task
-Instanzen aufgeschoben wird, bis sie tatsächlich benötigt werden. Der ManifestProducerTask
-Eingabewert wird auf einen Provider
-Wert 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 explizit angefordert werden. Dies kann beispielsweise im Rahmen eines Gradle-Aufrufs passieren, wenn Sie ./gradlew
debugManifestProducer
ausführen oder wenn die Ausgabe von ManifestProducerTask
mit einer anderen Aufgabe verbunden ist und ihr Wert erforderlich wird.
Sie schreiben zwar benutzerdefinierte Aufgaben, die Eingaben verwenden und/oder Ausgaben erzeugen, aber AGP bietet keinen direkten öffentlichen Zugriff auf eigene Aufgaben. Sie sind ein Implementierungsdetail, das sich von Version zu Version ändern kann. Stattdessen bietet AGP die Variant API und Zugriff auf die Ausgabe seiner Aufgaben oder Build-Artefakte, die Sie lesen und transformieren können. Weitere Informationen finden Sie in diesem Dokument unter Variant API, Artifacts, and Tasks.
Gradle-Build-Phasen
Das Erstellen eines Projekts ist von Natur aus ein komplizierter und ressourcenaufwendiger Prozess. Es gibt verschiedene Funktionen wie die Vermeidung der Aufgabenkonfiguration, die Überprüfung auf Aktualität und das Konfigurations-Caching, die dazu beitragen, die Zeit 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 verschiedenen Gradle-Build-Phasen (Initialisierung, Konfiguration und Ausführung) strenge Regeln einhalten. In diesem Leitfaden konzentrieren wir uns auf die Konfigurations- und Ausführungsphasen. Weitere Informationen zu allen Phasen finden Sie im Gradle-Build-Lebenszyklus.
Konfigurationsphase
In der Konfigurationsphase werden die Build-Skripts für alle Projekte, die Teil des Builds sind, ausgewertet, die Plug-ins werden angewendet und Build-Abhängigkeiten werden aufgelöst. In dieser Phase sollte der Build mit DSL-Objekten konfiguriert und Aufgaben und ihre Eingaben sollten verzögert registriert werden.
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 auf Eingaben zu beschränken, die nicht von den Build-Skripts selbst abhängen.
Das bedeutet, dass Sie keine externen Programme ausführen, keine Daten aus dem Netzwerk lesen und keine langen Berechnungen durchführen sollten, die als ordnungsgemäße Task
-Instanzen auf 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
markierten Task
-Klassenmethoden ausgeführt. Während der Ausführung von Aufgaben dürfen Sie Eingaben (z. B. Dateien) lesen und Lazy-Provider durch Aufrufen von Provider<T>.get()
auflösen. Wenn Lazy-Provider auf diese Weise aufgelöst werden, wird eine Reihe von map()
- oder flatMap()
-Aufrufen gestartet, die den in den Providern enthaltenen Informationen zur Aufgabenabhängigkeit folgen. Aufgaben werden verzögert ausgeführt, um die erforderlichen Werte zu materialisieren.
Variant API, Artefakte und Aufgaben
Die Variant API ist ein Erweiterungsmechanismus im Android-Gradle-Plug-in, mit dem Sie die verschiedenen Optionen bearbeiten können, die normalerweise mit der DSL in Build-Konfigurationsdateien festgelegt werden und den Android-Build beeinflussen. Über die Variant API haben Sie auch Zugriff auf Zwischen- und endgültige Artefakte, die vom 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-Lifecycle-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 verfügbar gemacht. Sie dürfen nicht versuchen, Instanzen der Task
-Objekte abzurufen oder 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 die Task
-Instanzen zu erstellen und auszuführen, die wiederum die Build-Artefakte erzeugen. Die wichtigsten Schritte bei der Erstellung von Variant
-Objekten werden von Callbacks gefolgt, mit denen Sie Änderungen an bestimmten Objekten vornehmen können, die im Rahmen eines Builds erstellt wurden. Alle Callbacks erfolgen während der Konfigurationsphase (auf dieser Seite beschrieben) und müssen schnell ausgeführt werden. Komplizierte Aufgaben sollten stattdessen auf entsprechende Task
-Instanzen während der Ausführungsphase verschoben werden.
- DSL-Parsing: Hier werden Build-Skripts ausgewertet und die verschiedenen Eigenschaften der Android-DSL-Objekte aus dem
android
-Block werden erstellt und festgelegt. Die in den folgenden Abschnitten beschriebenen Variant API-Callbacks werden ebenfalls in dieser Phase 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 auf Grundlage der Daten in den DSL-Objekten erstellt.DSL-Sperrung: DSL ist jetzt gesperrt und Änderungen sind nicht mehr möglich.
beforeVariants()
: ÜberVariantBuilder
kann dieser Callback beeinflussen, welche Komponenten erstellt werden und welche Eigenschaften sie haben. Es sind weiterhin Änderungen am Build-Ablauf und an den erstellten Artefakten möglich.Varianten erstellen: Die Liste der Komponenten und Artefakte, die erstellt werden, ist jetzt endgültig und kann nicht mehr geändert werden.
onVariants()
: In diesem Callback haben 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.Sperren von Varianten: Variantenobjekte sind jetzt gesperrt und Änderungen sind nicht mehr möglich.
Erstellte Aufgaben:
Variant
-Objekte und ihreProperty
-Werte werden verwendet, um dieTask
-Instanzen zu erstellen, die für die Ausführung des Builds erforderlich sind.
AGP führt 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 mit der DSL des Android-Blocks zu verwenden und jede benutzerdefinierte imperative Logik in buildSrc
oder externe Plug-ins zu verschieben. Sie können sich auch die buildSrc
-Beispiele in unserem GitHub-Repository mit Gradle-Rezepten ansehen, um zu erfahren, wie Sie ein Plug-in in Ihrem Projekt erstellen. Hier ist ein Beispiel für die Registrierung 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 Anwendungsfälle an, die Ihr Plug-in in den einzelnen Callbacks unterstützen kann:
finalizeDsl(callback: (DslExtensionT) -> Unit)
In diesem Callback können Sie auf die DSL-Objekte zugreifen und sie ändern, die durch das Parsen der Informationen aus dem android
-Block in den Build-Dateien erstellt wurden.
Diese DSL-Objekte werden verwendet, um Varianten in späteren Phasen des Builds zu initialisieren und zu konfigurieren. Sie können beispielsweise programmatisch neue Konfigurationen erstellen oder Eigenschaften überschreiben. Beachten Sie jedoch, dass alle Werte zur Konfigurationszeit aufgelöst werden müssen und daher nicht von externen Eingaben abhängen dürfen.
Nachdem dieser Callback ausgeführt wurde, sind die DSL-Objekte nicht mehr nützlich. Sie sollten keine Referenzen mehr auf sie haben 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 Phase des Builds erhalten Sie Zugriff auf VariantBuilder
-Objekte, die die zu erstellenden Varianten und ihre Eigenschaften bestimmen. Sie können beispielsweise bestimmte Varianten oder 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 zur Konfigurationszeit 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 akzeptiert optional ein VariantSelector
, das Sie über die Methode selector()
für das androidComponentsExtension
abrufen können. Damit können Sie Komponenten filtern, die am Callback-Aufruf beteiligt sind, basierend auf ihrem Namen, Build-Typ oder Produktvarianten.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
Wenn onVariants()
aufgerufen wird, sind alle Artefakte, die von AGP erstellt werden, bereits festgelegt. Sie können sie also nicht mehr deaktivieren. 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 erst aufgelöst werden, wenn die Aufgaben von AGP ausgeführt werden, können Sie sie problemlos mit Anbietern aus Ihren eigenen benutzerdefinierten Aufgaben verknüpfen, 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
Ihr Plug-in kann verschiedene Arten von generierten Quellen beitragen, 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 sehen Sie, wie Sie dem Java-Quellsatz mithilfe der Funktion addStaticSourceDirectory()
einen benutzerdefinierten Quellordner namens ${variant.name}
hinzufügen. Die Android-Toolchain verarbeitet diesen Ordner dann.
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
Weitere Informationen finden Sie im addJavaSource-Rezept.
In diesem Code-Snippet wird gezeigt, wie Sie dem Quellsatz res
ein Verzeichnis mit Android-Ressourcen hinzufügen, die aus einer benutzerdefinierten Aufgabe generiert wurden. 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 Rezept zum Hinzufügen benutzerdefinierter Assets.
Auf Artefakte zugreifen und sie ändern
Mit AGP können Sie nicht nur einfache Eigenschaften der Variant
-Objekte ändern, sondern auch Zwischen- und endgültige Artefakte lesen oder transformieren, die während des Builds erstellt werden. Sie können beispielsweise den endgültigen, zusammengeführten Inhalt der Datei AndroidManifest.xml
in einem 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 für die Klasse Artifact
. Jeder Artefakttyp hat bestimmte Attribute, die nützlich sind:
Kardinalität
Die Kardinalität eines Artifact
gibt die Anzahl der FileSystemLocation
-Instanzen an, also die Anzahl der Dateien oder Verzeichnisse des Artefakttyps. Informationen zur Kardinalität eines Artefakts erhalten Sie, indem Sie die übergeordnete Klasse prüfen: Artefakte mit einem 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. Dieser kann entweder RegularFile
oder Directory
sein.
Unterstützte Vorgänge
Jede Artifact
-Klasse kann eine der folgenden Schnittstellen implementieren, um anzugeben, welche Vorgänge sie unterstützt:
Transformable
: Ermöglicht die Verwendung einesArtifact
als Eingabe für einenTask
, der beliebige Transformationen darauf ausführt und eine neue Version desArtifact
ausgibt.Appendable
: Gilt nur für Artefakte, die Unterklassen vonArtifact.Multiple
sind. Das bedeutet, dass dieArtifact
erweitert werden kann. Mit einer benutzerdefiniertenTask
können also neue Instanzen diesesArtifact
-Typs erstellt werden, die der vorhandenen Liste hinzugefügt werden.Replaceable
: Gilt nur für Artefakte, die Unterklassen vonArtifact.Single
sind. Ein austauschbaresArtifact
kann durch eine völlig neue Instanz ersetzt werden, die als Ausgabe einesTask
erstellt wird.
Zusätzlich zu den drei Vorgängen zum Ändern von Artefakten unterstützt jedes Artefakt einen get()
-Vorgang (oder getAll()
), der ein Provider
mit der endgültigen Version des Artefakts zurückgibt (nachdem alle Vorgänge daran abgeschlossen sind).
Mehrere Plug-ins können der Pipeline über den onVariants()
-Callback beliebig viele Vorgänge für Artefakte hinzufügen. AGP sorgt dafür, dass sie richtig verkettet werden, sodass alle Aufgaben zur richtigen Zeit ausgeführt werden und Artefakte korrekt erstellt und aktualisiert werden. Wenn bei einem Vorgang Ausgaben durch Anhängen, Ersetzen oder Transformieren geändert werden, werden die aktualisierten Artefakte beim nächsten Vorgang als Eingaben verwendet.
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 auf eine Instanz von Artifacts
zugreifen können.
Sie können dann Ihr benutzerdefiniertes TaskProvider
übergeben, um ein TaskBasedOperation
-Objekt (1) zu erhalten, und es verwenden, um seine 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 wird, die Sie transformieren möchten.
Schließlich übergeben Sie den Typ Artifact
an eine Methode, die den ausgewählten Vorgang für das *OperationRequest
-Objekt darstellt, das Sie zurückerhalten, 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
eine SingleArtifact
und eine 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 in der Klasse TaskBasedOperation
, die für andere Kombinationen von Artifact
-Kardinalität und FileSystemLocation
-Typen funktionieren.
Weitere Informationen zum Erweitern von AGP finden Sie in den folgenden Abschnitten des Gradle-Buildsystem-Handbuchs:
- Benutzerdefinierte Gradle-Plug-ins entwickeln
- Gradle-Plug-ins implementieren
- Benutzerdefinierte Gradle-Aufgabentypen entwickeln
- Lazy Configuration
- Aufgabenkonfiguration vermeiden