Wtyczka Androida do obsługi Gradle (AGP) to oficjalny system kompilacji aplikacji na Androida. Obejmuje ona obsługę kompilowania wielu różnych typów źródeł i łączenia ich w aplikację, którą można uruchomić na fizycznym urządzeniu z Androidem lub w emulatorze.
AGP zawiera punkty rozszerzeń, które umożliwiają wtyczkom kontrolowanie danych wejściowych kompilacji i rozszerzanie jej funkcjonalności za pomocą nowych kroków, które można zintegrować ze standardowymi zadaniami kompilacji. Poprzednie wersje AGP nie miały oficjalnych interfejsów API wyraźnie oddzielonych od implementacji wewnętrznych. Od wersji 7.0 AGP ma zestaw oficjalnych, stabilnych interfejsów API, na których możesz polegać.
Cykl życia interfejsu AGP API
AGP stosuje cykl życia funkcji Gradle, aby określać stan interfejsów API:
- Wewnętrzne: nie są przeznaczone do użytku publicznego.
- W fazie rozwoju: dostępne do użytku publicznego, ale nie są ostateczne, co oznacza, że w wersji finalnej mogą nie być wstecznie kompatybilne.
- Publiczna: dostępna do użytku publicznego i stabilna.
- Wycofane: nie są już obsługiwane i zostały zastąpione nowymi interfejsami API.
Zasady wycofywania
AGP rozwija się dzięki wycofywaniu starych interfejsów API i zastępowaniu ich nowymi, stabilnymi interfejsami API oraz nowym językiem DSL (Domain Specific Language). Ten proces będzie obejmować kilka wersji AGP. Więcej informacji znajdziesz w harmonogramie migracji interfejsu AGP API/DSL.
Gdy interfejsy API AGP zostaną wycofane (w ramach tej migracji lub w innych okolicznościach), nadal będą dostępne w bieżącej wersji głównej, ale będą generować ostrzeżenia. Wycofane interfejsy API zostaną całkowicie usunięte z AGP w kolejnej wersji głównej. Jeśli na przykład interfejs API zostanie wycofany w AGP 7.0, będzie dostępny w tej wersji i będzie generować ostrzeżenia. Ten interfejs API nie będzie już dostępny w AGP 8.0.
Przykłady nowych interfejsów API używanych w przypadku typowych dostosowań kompilacji znajdziesz w przepisach na wtyczkę Androida do Gradle. Zawierają przykłady typowych dostosowań kompilacji. Więcej informacji o nowych interfejsach API znajdziesz w naszej dokumentacji referencyjnej.
Podstawy kompilacji Gradle
Ten przewodnik nie obejmuje całego systemu kompilacji Gradle. Zawiera jednak minimalny zestaw pojęć niezbędnych do integracji z naszymi interfejsami API, a także linki do głównej dokumentacji Gradle, w której znajdziesz więcej informacji.
Zakładamy, że masz podstawową wiedzę o tym, jak działa Gradle, w tym jak konfigurować projekty, edytować pliki kompilacji, stosować wtyczki i uruchamiać zadania. Aby poznać podstawy Gradle w kontekście AGP, zapoznaj się z artykułem Konfigurowanie kompilacji. Ogólne informacje o dostosowywaniu wtyczek Gradle znajdziesz w artykule Developing Custom Gradle Plugins (Tworzenie niestandardowych wtyczek Gradle).
Słowniczek typów leniwych Gradle
Gradle oferuje kilka typów, które działają „leniwie” lub pomagają odłożyć złożone obliczenia lub Task
tworzenie na późniejsze etapy kompilacji. Te typy są podstawą wielu interfejsów API Gradle i AGP. Poniżej znajdziesz listę głównych typów Gradle, które biorą udział w leniwej egzekucji, oraz ich kluczowe metody.
Provider<T>
- Zwraca wartość typu
T
(gdzie „T” oznacza dowolny typ), którą można odczytać w fazie wykonywania za pomocąget()
lub przekształcić w nową wartość typuProvider<S>
(gdzie „S” oznacza inny typ) za pomocą metodmap()
,flatMap()
izip()
. Pamiętaj, że metodyget()
nie należy wywoływać podczas fazy konfiguracji.map()
: przyjmuje funkcję lambda i zwracaProvider
typuS
,Provider<S>
. Argument lambda funkcjimap()
przyjmuje wartośćT
i zwraca wartośćS
. Funkcja lambda nie jest wykonywana od razu, ale jej wykonanie jest odroczone do momentu, w którym na wynikowym obiekcieProvider<S>
zostanie wywołana funkcjaget()
, co sprawia, że cały łańcuch jest leniwy.flatMap()
: akceptuje też funkcję LAMBDA i tworzyProvider<S>
, ale funkcja LAMBDA przyjmuje wartośćT
i tworzyProvider<S>
(zamiast tworzyć wartośćS
bezpośrednio). Użyj funkcji flatMap(), gdy nie można określić wartości S w momencie konfiguracji i możesz uzyskać tylkoProvider<S>
. W praktyce, jeśli użyjeszmap()
i uzyskasz typ wynikuProvider<Provider<S>>
, prawdopodobnie oznacza to, że zamiast tego należało użyćflatMap()
.zip()
: Umożliwia połączenie 2 instancjiProvider
w celu utworzenia nowej instancjiProvider
o wartości obliczonej za pomocą funkcji, która łączy wartości z 2 instancji wejściowychProviders
.
Property<T>
- Implementuje interfejs
Provider<T>
, więc udostępnia też wartość typuT
. W przeciwieństwie do parametruProvider<T>
, który jest przeznaczony tylko do odczytu, możesz też ustawić wartość parametruProperty<T>
. Możesz to zrobić na 2 sposoby:- Ustaw wartość typu
T
bezpośrednio, gdy jest dostępna, bez konieczności odroczonych obliczeń. - Ustaw inne
Provider<T>
jako źródło wartościProperty<T>
. W tym przypadku wartośćT
jest materializowana tylko wtedy, gdy wywoływana jest funkcjaProperty.get()
.
- Ustaw wartość typu
TaskProvider
- Implementuje
Provider<Task>
. Aby wygenerowaćTaskProvider
, użyjtasks.register()
, a nietasks.create()
. Dzięki temu zadania będą tworzone tylko wtedy, gdy będą potrzebne. Możesz użyćflatMap()
, aby uzyskać dostęp do danych wyjściowychTask
przed utworzeniemTask
. Może to być przydatne, jeśli chcesz użyć danych wyjściowych jako danych wejściowych dla innych instancjiTask
.
Dostawcy i ich metody transformacji są niezbędni do leniwego konfigurowania danych wejściowych i wyjściowych zadań, czyli bez konieczności tworzenia wszystkich zadań z góry i rozwiązywania wartości.
Dostawcy zawierają też informacje o zależnościach między zadaniami. Gdy utworzysz Provider
, przekształcając dane wyjściowe Task
, ten Task
staje się niejawną zależnością Provider
i będzie tworzony oraz uruchamiany za każdym razem, gdy zostanie rozwiązana wartość Provider
, np. gdy będzie potrzebny innemu Task
.
Oto przykład rejestrowania 2 zadań, GitVersionTask
i ManifestProducerTask
, z odroczeniem tworzenia instancji Task
do momentu, w którym będą one rzeczywiście potrzebne. Wartość wejściowa ManifestProducerTask
jest ustawiana na wartość aProvider
uzyskaną z danych wyjściowych funkcji GitVersionTask
, więc ManifestProducerTask
jest pośrednio zależna od 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))
}
Te 2 zadania zostaną wykonane tylko wtedy, gdy użytkownik wyraźnie o to poprosi. Może to nastąpić w ramach wywołania Gradle, np. jeśli uruchomisz polecenie ./gradlew
debugManifestProducer
lub jeśli dane wyjściowe polecenia ManifestProducerTask
są połączone z innym zadaniem i jego wartość staje się wymagana.
Będziesz pisać niestandardowe zadania, które wykorzystują dane wejściowe lub generują dane wyjściowe, ale AGP nie oferuje publicznego dostępu do własnych zadań. Są one szczegółami implementacji, które mogą się zmieniać w kolejnych wersjach. Zamiast tego AGP udostępnia interfejs Variant API i dostęp do wyników swoich zadań lub artefaktów kompilacji, które możesz odczytywać i przekształcać. Więcej informacji znajdziesz w sekcji Interfejs API wariantów, artefakty i zadania w tym dokumencie.
Fazy kompilacji Gradle
Tworzenie projektu jest z natury skomplikowanym i wymagającym zasobów procesem. Istnieją różne funkcje, takie jak unikanie konfiguracji zadań, aktualne sprawdzanie i funkcja buforowania konfiguracji, które pomagają zminimalizować czas poświęcony na powtarzalne lub niepotrzebne obliczenia.
Aby zastosować niektóre z tych optymalizacji, skrypty i wtyczki Gradle muszą przestrzegać ścisłych reguł w każdej z odrębnych faz kompilacji Gradle: inicjowania, konfiguracji i wykonywania. W tym przewodniku skupimy się na fazach konfiguracji i wdrażania. Więcej informacji o wszystkich fazach znajdziesz w przewodniku po cyklu życia kompilacji Gradle.
Faza konfiguracji
W fazie konfiguracji oceniane są skrypty kompilacji wszystkich projektów, które są częścią kompilacji, stosowane są wtyczki i rozwiązywane są zależności kompilacji. W tej fazie należy skonfigurować kompilację za pomocą obiektów DSL i zarejestrować zadania oraz ich dane wejściowe w sposób odroczony.
Faza konfiguracji jest zawsze uruchamiana niezależnie od tego, które zadanie ma zostać wykonane, dlatego szczególnie ważne jest, aby była jak najprostsza i aby żadne obliczenia nie zależały od danych wejściowych innych niż same skrypty kompilacji.
Oznacza to, że nie należy wykonywać programów zewnętrznych ani odczytywać danych z sieci ani przeprowadzać długich obliczeń, które można odłożyć do fazy wykonania jako odpowiednie instancje Task
.
Faza wykonania
W fazie wykonywania realizowane są żądane zadania i ich zadania zależne. W szczególności wykonywane są metody klasy Task
oznaczone symbolem @TaskAction
. Podczas wykonywania zadania możesz odczytywać dane wejściowe (np. pliki) i rozwiązywać leniwych dostawców, wywołując funkcję Provider<T>.get()
. Rozwiązywanie problemów z leniwymi dostawcami w ten sposób rozpoczyna sekwencję wywołań map()
lub flatMap()
, które są zgodne z informacjami o zależnościach zadań zawartymi w dostawcy. Zadania są wykonywane z opóźnieniem, aby uzyskać wymagane wartości.
Interfejs API wariantów, artefakty i zadania
Interfejs Variant API to mechanizm rozszerzający wtyczkę Androida do Gradle, który umożliwia manipulowanie różnymi opcjami, zwykle ustawianymi za pomocą DSL w plikach konfiguracji kompilacji, które mają wpływ na kompilację Androida. Interfejs Variant API umożliwia też dostęp do artefaktów pośrednich i końcowych utworzonych przez kompilację, takich jak pliki klas, scalony manifest czy pliki APK/AAB.
Proces kompilacji Androida i punkty rozszerzeń
Podczas interakcji z AGP używaj specjalnie utworzonych punktów rozszerzeń zamiast rejestrować typowe wywołania zwrotne cyklu życia Gradle (np. afterEvaluate()
) lub konfigurować jawne zależności Task
. Zadania utworzone przez AGP są traktowane jako szczegóły implementacji i nie są udostępniane jako publiczny interfejs API. Musisz unikać
prób uzyskania instancji obiektów Task
lub zgadywania nazw Task
i bezpośredniego dodawania wywołań zwrotnych lub zależności do tych obiektów Task
.
Aby utworzyć i wykonać instancje Task
, które z kolei generują artefakty kompilacji, AGP wykonuje te czynności: Główne etapy tworzenia obiektuVariant
są wykonywane po wywołaniach zwrotnych, które umożliwiają wprowadzanie zmian w niektórych obiektach utworzonych w ramach kompilacji. Pamiętaj, że wszystkie wywołania zwrotne występują w fazie konfiguracji (opisanej na tej stronie) i muszą działać szybko, odkładając wszelkie skomplikowane zadania na odpowiednie instancje Task
w fazie wykonania.
- Parsowanie DSL: w tym momencie oceniane są skrypty kompilacji, a także tworzone i ustawiane są różne właściwości obiektów DSL Androida z bloku
android
. Podczas tej fazy rejestrowane są też wywołania zwrotne interfejsu Variant API opisane w kolejnych sekcjach. finalizeDsl()
: wywołanie zwrotne, które umożliwia zmianę obiektów DSL przed ich zablokowaniem na potrzeby tworzenia komponentów (wariantów). ObiektyVariantBuilder
są tworzone na podstawie danych zawartych w obiektach DSL.Blokowanie DSL: DSL jest teraz zablokowany i nie można już wprowadzać zmian.
beforeVariants()
: ta funkcja zwrotna może wpływać na to, które komponenty są tworzone, i na niektóre ich właściwości za pomocą funkcjiVariantBuilder
. Nadal umożliwia modyfikowanie procesu kompilacji i wytwarzanych artefaktów.Tworzenie wariantu: lista komponentów i artefaktów, które zostaną utworzone, jest już ostateczna i nie można jej zmienić.
onVariants()
: w tym wywołaniu zwrotnym uzyskujesz dostęp do utworzonych obiektówVariant
i możesz ustawiać wartości lub dostawców dla wartościProperty
, które zawierają, aby były obliczane z opóźnieniem.Blokowanie wariantów: obiekty wariantów są teraz zablokowane i nie można już wprowadzać w nich zmian.
Utworzone zadania: obiekty
Variant
i ich wartościProperty
są używane do tworzenia instancjiTask
niezbędnych do przeprowadzenia kompilacji.
AGP wprowadza AndroidComponentsExtension
, który umożliwia rejestrowanie wywołań zwrotnych dla finalizeDsl()
, beforeVariants()
i onVariants()
.
Rozszerzenie jest dostępne w skryptach kompilacji w bloku androidComponents
:
// This is used only for configuring the Android build through DSL.
android { ... }
// The androidComponents block is separate from the DSL.
androidComponents {
finalizeDsl { extension ->
...
}
}
Zalecamy jednak, aby skrypty kompilacji służyły tylko do deklaratywnej konfiguracji za pomocą DSL bloku androida i przenosić niestandardową logikę imperatywną do buildSrc
lub zewnętrznych wtyczek. Możesz też zapoznać się z buildSrc
przykładami w naszym repozytorium GitHub z przepisami Gradle, aby dowiedzieć się, jak utworzyć wtyczkę w projekcie. Oto przykład rejestrowania wywołań zwrotnych z kodu wtyczki:
abstract class ExamplePlugin: Plugin<Project> {
override fun apply(project: Project) {
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.finalizeDsl { extension ->
...
}
}
}
Przyjrzyjmy się dostępnym wywołaniom zwrotnym i rodzajom przypadków użycia, które wtyczka może obsługiwać w każdym z nich:
finalizeDsl(callback: (DslExtensionT) -> Unit)
W tym wywołaniu zwrotnym możesz uzyskać dostęp do obiektów DSL utworzonych przez przeanalizowanie informacji z bloku android
w plikach kompilacji i je zmodyfikować.
Te obiekty DSL będą używane do inicjowania i konfigurowania wariantów w późniejszych fazach kompilacji. Możesz na przykład programowo tworzyć nowe konfiguracje lub zastępować właściwości, ale pamiętaj, że wszystkie wartości muszą być rozwiązywane w momencie konfiguracji, więc nie mogą zależeć od żadnych danych wejściowych z zewnątrz.
Po zakończeniu wykonywania tego wywołania zwrotnego obiekty DSL nie są już przydatne i nie należy już przechowywać do nich odwołań ani modyfikować ich wartości.
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()
Na tym etapie tworzenia uzyskujesz dostęp do obiektów VariantBuilder
, które określają warianty, jakie zostaną utworzone, oraz ich właściwości. Możesz na przykład programowo wyłączyć określone warianty lub ich testy albo zmienić wartość właściwości (np. minSdk
) tylko w przypadku wybranego wariantu. Podobnie jak w przypadku
finalizeDsl()
wszystkie podane wartości muszą być rozpoznawane w momencie konfiguracji i nie mogą zależeć od danych wejściowych z zewnątrz. Po zakończeniu wykonywania wywołania zwrotnego beforeVariants()
nie można modyfikować obiektów VariantBuilder
.
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
Wywołanie zwrotne beforeVariants()
opcjonalnie przyjmuje wartość VariantSelector
, którą możesz uzyskać za pomocą metody selector()
w obiekcie androidComponentsExtension
. Możesz go użyć do filtrowania komponentów uczestniczących w wywołaniu zwrotnym na podstawie ich nazwy, typu kompilacji lub wersji produktu.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
W momencie wywołania funkcji onVariants()
wszystkie artefakty, które zostaną utworzone przez AGP, są już określone, więc nie można ich już wyłączyć. Możesz jednak zmodyfikować niektóre wartości używane w przypadku zadań, ustawiając je dla atrybutów Property
w obiektach Variant
. Wartości Property
zostaną rozwiązane dopiero po wykonaniu zadań AGP, więc możesz je bezpiecznie połączyć z dostawcami z własnych zadań niestandardowych, które wykonają wszelkie wymagane obliczenia, w tym odczyt z zewnętrznych danych wejściowych, takich jak pliki lub sieć.
// 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() })
}
Wnoszenie wygenerowanych źródeł do kompilacji
Wtyczka może generować kilka rodzajów źródeł, takich jak:
- Kod aplikacji w katalogu
java
- Zasoby Androida w katalogu
res
- zasoby Java w katalogu
resources
; - zasoby Androida w katalogu
assets
.
Pełną listę źródeł, które możesz dodać, znajdziesz w interfejsie Sources API.
Ten fragment kodu pokazuje, jak dodać do zestawu źródeł Java niestandardowy folder źródłowy o nazwie ${variant.name}
za pomocą funkcji addStaticSourceDirectory()
. Następnie łańcuch narzędzi Androida przetwarza ten folder.
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
Więcej informacji znajdziesz w przepisie addJavaSource.
Ten fragment kodu pokazuje, jak dodać katalog z zasobami Androida wygenerowanymi na podstawie niestandardowego zadania do zestawu źródeł res
. W przypadku innych typów źródeł proces jest podobny.
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.
...
}
}
Więcej informacji znajdziesz w przepisie addCustomAsset.
Dostęp do artefaktów i ich modyfikowanie
Oprócz modyfikowania prostych właściwości obiektów Variant
AGP zawiera też mechanizm rozszerzeń, który umożliwia odczytywanie lub przekształcanie artefaktów pośrednich i końcowych wygenerowanych podczas kompilacji. Możesz na przykład odczytać zawartość końcowego, scalonego pliku AndroidManifest.xml
w niestandardowym Task
, aby ją przeanalizować, lub całkowicie zastąpić ją zawartością pliku manifestu wygenerowanego przez niestandardowy Task
.
Listę artefaktów, które są obecnie obsługiwane, znajdziesz w dokumentacji referencyjnej klasy Artifact
. Każdy typ artefaktu ma określone właściwości, które warto znać:
Moc zbioru
Moc zbioru Artifact
to liczba jego FileSystemLocation
instancji, czyli liczba plików lub katalogów danego typu artefaktu. Informacje o kardynalności artefaktu możesz uzyskać, sprawdzając jego klasę nadrzędną: artefakty z pojedynczym FileSystemLocation
będą podklasą Artifact.Single
, a artefakty z wieloma instancjami FileSystemLocation
będą podklasą Artifact.Multiple
.
FileSystemLocation
typ
Możesz sprawdzić, czy Artifact
reprezentuje pliki czy katalogi, sprawdzając jego sparametryzowany typ FileSystemLocation
, który może być RegularFile
lub Directory
.
Obsługiwane operacje
Każda klasa Artifact
może implementować dowolny z tych interfejsów, aby wskazać, które operacje obsługuje:
Transformable
: umożliwia użycieArtifact
jako danych wejściowych dlaTask
, który wykonuje na nim dowolne przekształcenia i zwraca nową wersjęArtifact
.Appendable
: dotyczy tylko artefaktów, które są podklasamiArtifact.Multiple
. Oznacza to, że doArtifact
można dodawać elementy, czyli niestandardowyTask
może tworzyć nowe instancje tego typuArtifact
, które zostaną dodane do istniejącej listy.Replaceable
: dotyczy tylko artefaktów, które są podklasamiArtifact.Single
. WymiennyArtifact
można zastąpić zupełnie nową instancją, która jest wynikiem działaniaTask
.
Oprócz 3 operacji modyfikujących artefakty każdy artefakt obsługuje operację get()
(lub getAll()
), która zwraca Provider
z ostateczną wersją artefaktu (po zakończeniu wszystkich operacji na nim).
Wiele wtyczek może dodawać do potoku dowolną liczbę operacji na artefaktach z wywołania zwrotnego onVariants()
, a AGP zadba o ich prawidłowe połączenie, aby wszystkie zadania były wykonywane we właściwym czasie, a artefakty były prawidłowo tworzone i aktualizowane. Oznacza to, że gdy operacja zmieni dane wyjściowe przez dodanie, zastąpienie lub przekształcenie ich, następna operacja zobaczy zaktualizowaną wersję tych artefaktów jako dane wejściowe i tak dalej.
Punktem wejścia do rejestrowania operacji jest klasa Artifacts
.
Ten fragment kodu pokazuje, jak uzyskać dostęp do instancji Artifacts
z właściwości obiektu Variant
w wywołaniu zwrotnym onVariants()
.
Następnie możesz przekazać niestandardowy element TaskProvider
, aby uzyskać obiekt TaskBasedOperation
(1) i użyć go do połączenia jego wejść i wyjść za pomocą jednej z metod wiredWith*
(2).
Metoda, którą musisz wybrać, zależy od liczności i FileSystemLocation
typu zaimplementowanego przez Artifact
, który chcesz przekształcić.
Na koniec przekazujesz Artifact
do metody reprezentującej wybraną operację na obiekcie *OperationRequest
, który otrzymujesz w zamian, np. toAppendTo()
, toTransform()
lub 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)
}
W tym przykładzie MERGED_MANIFEST
to SingleArtifact
, a RegularFile
. Dlatego musimy użyć metody wiredWithFiles
, która przyjmuje 1 RegularFileProperty
jako dane wejściowe i 1 RegularFileProperty
jako dane wyjściowe. Istnieją inne wiredWith*
metody w klasie TaskBasedOperation
, które będą działać w przypadku innych kombinacji Artifact
liczności i FileSystemLocation
typów.
Więcej informacji o rozszerzaniu AGP znajdziesz w tych sekcjach podręcznika systemu kompilacji Gradle:
- Tworzenie niestandardowych wtyczek Gradle
- Implementowanie wtyczek Gradle
- Tworzenie niestandardowych typów zadań Gradle
- Leniwa konfiguracja
- Unikanie konfiguracji zadań