Wtyczka Androida do obsługi Gradle (AGP) to oficjalny system kompilacji aplikacji na Androida. Obejmuje ona kompilowanie wielu różnych typów źródeł i łączenie ich w aplikację, którą można uruchomić na fizycznym urządzeniu z Androidem lub w emulatorze.
Interfejs AGP zawiera punkty rozszerzeń umożliwiające wtyczce kontrolowanie danych wejściowych kompilacji i rozszerzenie 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 zawiera 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ślić stan interfejsów API:
- Do użytku wewnętrznego: nie jest przeznaczony do użytku publicznego.
- W fazie testów: dostępne dla użytkowników, ale nie są wersjami ostatecznymi, co oznacza, że w ostatecznej wersji mogą nie być zgodne z wcześniejszymi wersjami.
- Publiczna: stabilna wersja publiczna.
- Wycofany: nie jest już obsługiwany i został zastąpiony nowym interfejsem API.
Zasady wycofywania
AGP ewoluuje wraz z wycofaniem starych interfejsów API i zastąpieniem ich nowymi, stabilnymi interfejsami API oraz nowym językiem do zastosowań w domenie (DSL). Ta ewolucja obejmie wiele wersji interfejsu AGP. Więcej informacji znajdziesz w harmonogramie migracji interfejsów API i interfejsów DSL AGP.
Gdy wycofamy interfejsy AGP (np. w ramach tej migracji), nadal będą one dostępne w obecnej głównej wersji, ale będą generować ostrzeżenia. Wycofane interfejsy API zostaną całkowicie usunięte z pakietu AGP w kolejnej wersji głównej. Jeśli na przykład interfejs API został wycofany w wersji AGP 7.0, będzie on dostępny w tej wersji i wygeneruje ostrzeżenia. Ten interfejs API nie będzie już dostępny w AGP 8.0.
Przykłady nowych interfejsów API używanych w ramach typowych dostosowań kompilacji znajdziesz w przepisach wtyczki Gradle na Androida. Znajdziesz w nich 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 on jednak minimalny zestaw pojęć, który pomoże Ci w integracji z naszych interfejsami API, oraz linki do głównej dokumentacji Gradle, w której znajdziesz więcej informacji.
Zakładamy, że znasz podstawy działania Gradle, w tym konfigurowanie projektów, edytowanie plików kompilacji, stosowanie wtyczek i uruchamianie zadań. Podstawowe informacje o Gradle w odniesieniu do AGP znajdziesz w artykule Konfigurowanie kompilacji. Informacje o ogólnej strukturze dostosowywania wtyczek Gradle znajdziesz w artykule Tworzenie niestandardowych wtyczek Gradle.
Słownik typów nieaktywnych w Gradle
Gradle oferuje kilka typów działania, które działają „leniwie” lub pomagają opóźnić wykonywanie złożonych obliczeń bądź tworzenie Task
do późniejszych faz kompilacji. Te typy są podstawą wielu interfejsów API Gradle i AGP. Poniższa lista zawiera główne typy Gradle używane w opóźnionym wykonywaniu oraz ich kluczowe metody.
Provider<T>
- Dostarcza wartość typu
T
(gdzie „T” oznacza dowolny typ), którą można odczytać podczas fazy wykonywania za pomocą metodyget()
lub przekształcić w nową wartośćProvider<S>
(gdzie „S” oznacza inny typ) za pomocą metodmap()
,flatMap()
izip()
. Pamiętaj, że metodaget()
nigdy nie powinna być wywoływana na etapie konfiguracji.map()
: przyjmuje lambda i tworzyProvider
typuS
,Provider<S>
. Argument lambda funkcjimap()
przyjmuje wartośćT
i zwraca wartośćS
. Funkcja lambda nie jest wykonywana od razu. Jej wykonanie jest odroczone do momentu wywołania funkcjiget()
w wynikającym z niej obiekcieProvider<S>
, dzięki czemu cały łańcuch jest opóźniony.flatMap()
: przyjmuje funkcję lambda i zwraca wartośćProvider<S>
, ale funkcja lambda przyjmuje wartośćT
i zwraca wartośćProvider<S>
(zamiast bezpośrednio wartościS
). Użyj flatMap(), gdy S nie może zostać określony w czasie konfiguracji i możesz uzyskać tylkoProvider<S>
. Praktycznie rzecz biorąc, jeśli użyjesz funkcjimap()
, a w efekcie otrzymasz typ wynikuProvider<Provider<S>>
, prawdopodobnie powinieneś użyć funkcjiflatMap()
.zip()
: umożliwia połączenie 2 instancjiProvider
w celu utworzenia nowejProvider
z wartością obliczoną za pomocą funkcji łączącej wartości z 2 instancji wejściowychProviders
.
Property<T>
- Wdraża
Provider<T>
, więc również udostępnia wartość typuT
. W przeciwieństwie do parametruProvider<T>
, który jest przeznaczony tylko do odczytu, parametrProperty<T>
może też mieć ustawioną wartość. Możesz to zrobić na 2 sposoby:- Ustaw wartość typu
T
bezpośrednio, gdy jest dostępna, bez potrzeby odroczonego przetwarzania. - Jako źródła wartości
Property<T>
użyj innego parametruProvider<T>
. W tym przypadku wartośćT
jest materializowana tylko wtedy, gdy wywołana jest funkcjaProperty.get()
.
- Ustaw wartość typu
TaskProvider
- Wdroż
Provider<Task>
. Do wygenerowaniaTaskProvider
użyjtasks.register()
zamiasttasks.create()
. Dzięki temu zadania będą tworzone leniwie tylko wtedy, gdy są potrzebne. Za pomocąflatMap()
możesz uzyskać dostęp do danych wyjściowych elementuTask
przed utworzeniemTask
. Może to być przydatne, jeśli chcesz używać danych wyjściowych jako danych wejściowych dla innych instancjiTask
.
Dostawcy i ich metody transformacji są niezbędne do konfigurowania danych wejściowych i wyjściowych zadań w sposób leniwy, czyli bez konieczności tworzenia wszystkich zadań z wyprzedzeniem i rozwiązywania wartości.
Dostawcy przekazują też informacje o zależnościach zadań. Gdy utworzysz funkcję Provider
, przekształcając dane wyjściowe funkcji Task
, ta pierwsza stanie się jej domyślną zależnością i będzie tworzona oraz uruchamiana zawsze, gdy zostanie rozwiązana wartość funkcji Task
, np. gdy będzie to wymagane przez inną funkcję Task
.Provider
Provider
Oto przykład zarejestrowania 2 zadań: GitVersionTask
i ManifestProducerTask
, z odroczeniem utworzenia instancji Task
do momentu, gdy będą one faktycznie wymagane. Wartość wejściowa ManifestProducerTask
jest ustawiona na Provider
uzyskaną z danych wyjściowych GitVersionTask
, więc ManifestProducerTask
domyślnie zależy od wartości 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 będą wykonywane tylko wtedy, gdy zostanie wysłane odpowiednie żądanie. Może się to zdarzyć w ramach wywołania Gradle, na przykład gdy uruchomisz ./gradlew
debugManifestProducer
, lub gdy dane wyjściowe ManifestProducerTask
są połączone z jakimś innym zadaniem i ich wartość staje się wymagana.
Podczas gdy będziesz pisać niestandardowe zadania, które wykorzystują dane wejściowe lub generują dane wyjściowe, usługa AGPC nie udostępnia publicznie własnych zadań. Zawierają one szczegóły implementacji, które mogą się zmieniać w zależności od wersji. Zamiast tego AGP oferuje interfejs Variant API i dostęp do wyników jego zadań, czyli elementów buildu, które możesz odczytać i przekształcić. Więcej informacji znajdziesz w opisie interfejsu API wariantu, artefaktów i zadań w tym dokumencie.
Fazy kompilacji Gradle
Tworzenie projektu to z zasady skomplikowany proces, który wymaga wielu zasobów. Dostępne są różne funkcje, takie jak unikanie konfiguracji zadań, aktualne kontrole i funkcja buforowania konfiguracji, które pomagają zminimalizować czas poświęcany na powtarzalne lub niepotrzebne obliczenia.
Aby zastosować niektóre z tych optymalizacji, skrypty i wtyczki Gradle muszą przestrzegać ścisłych reguł na każdym z etapów kompilacji Gradle: inicjalizacji, konfiguracji i wykonania. W tym przewodniku skupimy się na konfiguracji i wykonaniu. Więcej informacji o wszystkich fazach znajdziesz w przewodniku po cyklu życia kompilacji Gradle.
Etap konfiguracji
W trakcie konfiguracji są oceniane skrypty kompilacji wszystkich projektów wchodzących w jej skład, stosowane są wtyczki, a zależności kompilacji są rozwiązywane. Ta faza służy do konfigurowania kompilacji za pomocą obiektów DSL oraz do leniwego rejestrowania zadań i ich danych wejściowych.
Etap konfiguracji jest zawsze uruchamiany niezależnie od tego, jakie zadanie ma zostać uruchomione, dlatego szczególnie ważne jest, aby nie przeprowadzał żadnych obliczeń i ogranicz wykonywanie obliczeń na podstawie danych wejściowych innych niż same skrypty kompilacji.
Oznacza to, że nie należy uruchamiać programów zewnętrznych ani odczytywać danych z sieci ani wykonywać długich obliczeń, które można odłożyć do fazy wykonywania jako odpowiednie instancje Task
.
Faza wykonania
Na etapie wykonywania są wykonywane żądane zadania i zadania zależne. Konkretnie uruchomione 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ązanie problemu leniwego dostawcy w ten sposób uruchamia sekwencję wywołań map()
lub flatMap()
, które są zgodne z informacjami o zależności zadań podanymi w dostawcy. Zadania są wykonywane leniwie w celu realizacji wymaganych wartości.
Interfejs API wariantów, artefakty i zadania
Interfejs Variant API to mechanizm rozszerzeń w pliku Android Gradle, który umożliwia manipulowanie różnymi opcjami, zwykle ustawianymi za pomocą języka DSL w plikach konfiguracji kompilacji, które wpływają na kompilację Androida. Interfejs Variant API zapewnia też dostęp do pośrednich i ostatecznych artefaktów tworzonych przez kompilację, takich jak pliki klasy, scalony plik manifestu czy pliki APK/AAB.
Proces kompilacji na Androida i punkty rozszerzeń
Podczas interakcji z AGP używaj specjalnie utworzonych punktów rozszerzenia zamiast rejestrować typowe wywołania cyklu życia Gradle (takie jak afterEvaluate()
) lub konfigurować jawne zależności Task
. Zadania tworzone przez AGP są uważane za szczegóły implementacji i nie są udostępniane jako publiczny interfejs API. Nie próbuj uzyskiwać instancji obiektów Task
, nie zgaduj nazw Task
ani nie dodawaj wywołań zwrotnych lub zależności bezpośrednio do tych obiektów Task
.
AGP wykonuje te czynności, aby utworzyć i wykonać instancje Task
, które z kolei generują artefakty kompilacji. Po głównych czynnościach związanych z tworzeniem obiektu Variant
następują wywołania zwrotne umożliwiające wprowadzenie zmian do określonych obiektów tworzonych w ramach kompilacji. Warto pamiętać, że wszystkie wywołania zwrotne występują podczas fazy konfiguracji (opisanej na tej stronie) i muszą działać szybko, co oznacza odroczenie wszelkich skomplikowanych zadań do odpowiednich instancji Task
w fazie wykonywania.
- Analizowanie DSL: w tym momencie są oceniane skrypty kompilacji oraz tworzone i ustawiane są różne właściwości obiektów DSL Androida z bloku
android
. Na tym etapie rejestrowane są też wywołania zwrotne interfejsu API wariantów opisane w poniższych sekcjach. finalizeDsl()
: Funkcja wywołania zwrotnego, która umożliwia zmianę obiektów DSL, zanim zostaną zablokowane na potrzeby tworzenia komponentu (wariantu). ObiektyVariantBuilder
są tworzone na podstawie danych zawartych w obiektach DSL.Blokowanie DSL: usługa DSL jest teraz zablokowana i nie można już wprowadzać zmian.
beforeVariants()
: to wywołanie zwrotne może wpływać na tworzone komponenty i niektóre z ich właściwości wVariantBuilder
. Nadal umożliwia wprowadzanie zmian w procesie kompilacji i w wygenerowanych artefaktach.Tworzenie wariantów: lista komponentów i elementów, które zostaną utworzone, jest już sfinalizowana i nie można jej zmienić.
onVariants()
: W tym wywołaniu zwrotnym uzyskujesz dostęp do utworzonych obiektówVariant
i możesz dla zawartych w nich wartościProperty
ustawić wartości lub dostawców, aby były obliczane z opóźnieniem.Blokowanie wariantów: obiekty wariantów są teraz zablokowane i nie można ich już zmieniać.
Utworzone zadania: obiekty (
Variant
) i ich wartościProperty
są używane do tworzenia instancjiTask
niezbędnych do wykonania kompilacji.
AGP wprowadza AndroidComponentsExtension
, który umożliwia rejestrowanie wywołań zwrotnych finalizeDsl()
, beforeVariants()
i onVariants()
.
Rozszerzenie jest dostępne w skryptach kompilacji za pomocą 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ą języka DSL bloku Androida, a dowolną niestandardową logikę imperatywną przenieść do buildSrc
lub zewnętrznych wtyczek. Aby dowiedzieć się, jak utworzyć w projekcie wtyczkę, możesz też przejrzeć przykłady buildSrc
w repozytorium z przepisami Gradle w GitHub. 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ę bliżej dostępnym funkcjom zwracania wartości i przypadkom użycia, które może obsługiwać Twój wtyczka:
finalizeDsl(callback: (DslExtensionT) -> Unit)
To wywołanie zwrotne umożliwia dostęp do utworzonych obiektów DSL i modyfikowanie ich przez analizowanie informacji z bloku android
w plikach kompilacji.
Te obiekty DSL będą używane do inicjowania i konfigurowania wariantów w późniejszych fazach kompilacji. Możesz na przykład automatycznie tworzyć nowe konfiguracje lub zastępować właściwości, ale pamiętaj, że wszystkie wartości muszą zostać potwierdzone na etapie konfiguracji, więc nie mogą opierać się na żadnych zewnętrznych danych wejściowych.
Po zakończeniu 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 kompilacji uzyskujesz dostęp do obiektów VariantBuilder
, które określają tworzone warianty i ich właściwości. Możesz na przykład za pomocą kodu 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 parametru finalizeDsl()
wszystkie podane przez Ciebie wartości muszą zostać rozwiązane w momencie konfiguracji i nie mogą zależeć od zewnętrznych danych wejściowych. Po zakończeniu wykonywania wywołania zwrotnego beforeVariants()
obiektów VariantBuilder
nie można modyfikować.
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
Opcjonalnie wywołanie zwrotne beforeVariants()
może przyjmować parametr VariantSelector
, który możesz uzyskać za pomocą metody selector()
obiektu androidComponentsExtension
. Możesz go używać do filtrowania komponentów korzystających z wywołania zwrotnego na podstawie nazwy, typu kompilacji lub rodzaju usługi.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
Przed wywołaniem funkcji onVariants()
wszystkie artefakty utworzone przez interfejs AGP są już ustawione, więc nie można ich już wyłączyć. Możesz jednak zmodyfikować niektóre wartości używane do zadań, ustawiając je w atrybutach Property
w obiektach Variant
. Wartości Property
są rozpoznawane tylko podczas wykonywania zadań AGP, więc możesz bezpiecznie połączyć je z dostawcami z własnych niestandardowych zadań, które będą wykonywać wymagane obliczenia, w tym odczyty 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() })
}
Przekaż wygenerowane źródła do kompilacji
Twój wtyczek może udostępniać kilka typów generowanych ź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 za pomocą funkcji addStaticSourceDirectory()
dodać do zbioru źródeł Javy niestandardowy folder źródeł o nazwie ${variant.name}
. Następnie narzędzia Androida przetwarzają 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ć do zbioru źródłowego res
katalog z zasobami Androida wygenerowanymi na podstawie zadania niestandardowego. 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 możliwości modyfikowania prostych właściwości obiektów Variant
AGP zawiera też mechanizm rozszerzeń, który umożliwia odczytywanie i przekształcanie artefaktów pośrednich i ostatecznych wygenerowanych podczas kompilacji. Możesz na przykład odczytać zawartość końcowego, scalonego pliku AndroidManifest.xml
w niestandardowym pliku Task
, aby go przeanalizować, lub całkowicie zastąpić jego zawartość zawartością pliku manifestu wygenerowanego przez niestandardowy plik Task
.
Listę elementów obecnie obsługiwanych znajdziesz w dokumentacji referencyjnej klasy Artifact
. Każdy typ artefaktu ma określone właściwości, które warto poznać:
Moc zbioru
Moc zbioru Artifact
reprezentuje liczbę instancji FileSystemLocation
, czyli liczbę plików lub katalogów typu artefaktu. Informacje o kardinalności artefaktu możesz uzyskać, sprawdzając jego klasę nadrzędną: artefakty z jednym FileSystemLocation
będą podklasą Artifact.Single
, a artefakty z wieloma instancjami FileSystemLocation
będą podklasą Artifact.Multiple
.
FileSystemLocation
typ
Aby sprawdzić, czy Artifact
reprezentuje pliki czy katalogi, sprawdź parametryzowany typ FileSystemLocation
, który może być albo RegularFile
, albo 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 wejścia dla funkcjiTask
, która wykonuje na nim dowolne przekształcenia i wyprowadza nową wersjęArtifact
.Appendable
: dotyczy tylko artefaktów, które są podklasamiArtifact.Multiple
. Oznacza to, że doArtifact
można dołączać elementy, czyli niestandardowy elementTask
może tworzyć nowe wystąpienia tego typuArtifact
, które zostaną dodane do istniejącej listy.Replaceable
: dotyczy tylko artefaktów, które są podklasamiArtifact.Single
. Zastępowalny elementArtifact
może zostać zastąpiony przez zupełnie nowy egzemplarz wygenerowany jako dane wyjściowe elementuTask
.
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 architektura AGP zapewnia, że są one prawidłowo powiązane w łańcuchu, tak aby wszystkie zadania były wykonywane w odpowiednim czasie, a artefakty były prawidłowo tworzone i aktualizowane. Oznacza to, że gdy operacja zmieni dane wyjściowe przez ich dodanie, zastąpienie lub przekształcenie, w następnej operacji zostanie przedstawiona zaktualizowana wersja artefaktów jako dane wejściowe itd.
Punkt wejścia do operacji rejestrowania to 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ć niestandardową zmienną TaskProvider
, aby uzyskać obiekt TaskBasedOperation
(1), i używać go do łączenia wejść i wyjść za pomocą jednej z metod wiredWith*
(2).
Dokładna metoda wyboru zależy od mocy zbioru i typu FileSystemLocation
zaimplementowanego przez obiekt Artifact
, który chcesz przekształcić.
Na koniec przekazujesz typ Artifact
do metody reprezentującej wybraną operację na obiekcie *OperationRequest
, która zwraca 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
i RegularFile
. Z tego powodu musimy użyć metody wiredWithFiles
, która przyjmuje jako dane wejściowe pojedyncze odwołanie RegularFileProperty
, a jako dane wyjściowe pojedynczą wartość RegularFileProperty
. W klasie TaskBasedOperation
są też inne metody wiredWith*
, które działają w przypadku innych kombinacji mocy zbioru Artifact
i typów FileSystemLocation
.
Aby dowiedzieć się więcej o rozszerzaniu AGP, przeczytaj te sekcje instrukcji systemu kompilacji Gradle:
- Tworzenie niestandardowych wtyczek Gradle
- Implementowanie wtyczek Gradle
- Tworzenie niestandardowych typów zadań Gradle
- Konfiguracja leniwego ładowania
- Unikaj konfiguracji zadań