Wtyczka Android Gradle (AGP) to oficjalny system kompilacji dla 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. Począwszy od wersji 7.0 platforma AGP udostępnia zestaw oficjalnych, stabilnych interfejsów API, na których można polegać.
Cykl życia interfejsu AGP API
AGP stosuje się do cyklu życia funkcji Gradle, aby określić stan swoich interfejsów API:
- Do użytku wewnętrznego: nie jest przeznaczony do użytku publicznego.
- Inkubacja: rozwiązania dostępne do użytku publicznego, ale nie ostateczne, co oznacza, że w ostatecznej wersji mogą nie być zgodne wstecznie.
- Publiczny: dostępny do użytku publicznego, stabilny.
- 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 wersji 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 modyfikacji kompilacji. Więcej informacji o nowych interfejsach API znajdziesz w naszej dokumentacji referencyjnej.
Podstawy kompilacji w Gradle
Ten przewodnik nie obejmuje całego systemu kompilacji Gradle. Omawiamy w nim jednak minimalny zestaw koncepcji, które ułatwiają integrację z naszymi interfejsami API, oraz linki do głównej dokumentacji Gradle, gdzie można się z nimi zapoznać.
Zakładamy, że znasz podstawy działania Gradle, w tym konfigurowanie projektów, edytowanie plików kompilacji, stosowanie wtyczek i uruchamianie zadań. Aby dowiedzieć się więcej o podstawach Gradle w związku z AGP, przeczytaj artykuł Konfigurowanie procesu kompilacji. Informacje o ogólnej platformie dostosowywania wtyczek Gradle znajdziesz w artykule Tworzenie niestandardowych wtyczek Gradle.
Glosariusz leniwego typu 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. Na liście poniżej znajdziesz główne typy Gradle używane w leniwym wykonaniu i ich kluczowe metody.
Provider<T>
- Udostępnia wartość typu
T
(gdzie „T” oznacza dowolny typ), którą można odczytać w trakcie fazy wykonywania za pomocąget()
lub przekształcić w nowyProvider<S>
(gdzie „S” oznacza inny typ) przy użyciu metodmap()
,flatMap()
izip()
. Pamiętaj, że metodaget()
nie powinna być nigdy 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 odraczane do momentu wywołania funkcjiget()
w wynikuProvider<S>
, przez co cały łańcuch staje się leniwy.flatMap()
: akceptuje również lambdę i zwraca wartośćProvider<S>
, ale lambda przyjmuje wartośćT
i zwraca wartośćProvider<S>
(zamiast bezpośrednio generować wartośćS
). Użyj flatMap(), gdy S nie może zostać określony w czasie konfiguracji i możesz uzyskać tylkoProvider<S>
. Ogólnie rzecz biorąc, jeśli po użyciu typu wynikumap()
otrzymujesz typ wynikuProvider<Provider<S>>
, prawdopodobnie musisz użyć parametruflatMap()
.zip()
: umożliwia połączenie 2 wystąpienia funkcjiProvider
w celu utworzenia nowej wartościProvider
, obliczonej za pomocą funkcji, która łączy wartości z 2 wejśćProviders
.
Property<T>
- Wdraża
Provider<T>
, więc również udostępnia wartość typuT
. W przeciwieństwie do parametruProvider<T>
, który jest 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 inny element
Provider<T>
jako źródło wartości parametruProperty<T>
. W tym przypadku wartośćT
jest zmaterializowany tylko wtedy, gdy wywołana jestProperty.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ą funkcjiflatMap()
możesz uzyskać dostęp do danych wyjściowych funkcjiTask
przed jej utworzeniem. Może to być przydatne, jeśli chcesz użyć tych danych jako danych wejściowych dla innych instancji funkcjiTask
.
Dostawcy i ich metody przekształcania są niezbędne do leniwego konfigurowania danych wejściowych i wyjściowych zadań, czyli bez konieczności wcześniejszego tworzenia wszystkich zadań i usuwania wartości.
Dostawcy mogą też przekazywać informacje o zależności między zadaniami. Gdy utworzysz Provider
przez przekształcenie danych wyjściowych Task
, ta funkcja Task
stanie się zależność domniemaną parametru Provider
i będzie tworzona i uruchamiana za każdym razem, gdy zostanie ustalona wartość obiektu Provider
, np. gdy wymaga tego inny element Task
.
Oto przykład rejestrowania 2 zadań GitVersionTask
i ManifestProducerTask
, przy czym tworzenie instancji Task
jest odkładane do momentu, gdy są one rzeczywiście potrzebne. Wartość wejściowa ManifestProducerTask
jest ustawiana na Provider
uzyskaną z wyjścia funkcji GitVersionTask
, więc ManifestProducerTask
pośrednio zależy 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 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ń. Są to szczegóły implementacji, które mogą się zmieniać w kolejnych wersjach. Zamiast tego udostępnia interfejs API wariantu i dostęp do danych wyjściowych jego zadań, czyli artefaktów tworzenia, które można odczytywać i przekształcać. 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 możliwe było zastosowanie niektórych z tych optymalizacji, skrypty i wtyczki Gradle muszą przestrzegać rygorystycznych reguł na każdym z różnych faz kompilacji Gradle: inicjowania, 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
Na etapie konfiguracji oceniane są skrypty kompilacji, które wchodzą w skład kompilacji, są stosowane wtyczki i usuwane są zależności kompilacji. Ta faza służy do konfigurowania kompilacji za pomocą obiektów DSL oraz do leniwego rejestrowania zadań i ich danych wejściowych.
Faza konfiguracji jest zawsze wykonywana niezależnie od tego, jakie zadanie zostało uruchomione, dlatego ważne jest, aby była jak najbardziej zwięzła i niezależna od danych wejściowych innych niż 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. W szczególności wykonywane są metody klasy Task
oznaczone jako @TaskAction
. Podczas wykonywania zadania możesz odczytywać dane z danych wejściowych (takich jak pliki) i rozwiązywać problemy 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 aplikacji na Androida i punkty rozszerzenia
Podczas interakcji z interfejsem AGP używaj specjalnie utworzonych punktów rozszerzenia zamiast rejestrować typowe wywołania zwrotne cyklu życia Gradle (np. afterEvaluate()
) lub konfigurując 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 poniższe kroki, aby utworzyć i wykonać swoje 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.
- Analiza DSL: następuje ocena skryptów kompilacji oraz utworzenie i ustalenie różnych właściwości obiektów DSL Androida z bloku
android
. W tej fazie są też rejestrowane wywołania zwrotne interfejsu Variant API opisane w następnych sekcjach. finalizeDsl()
: wywołanie zwrotne, które umożliwia zmianę obiektów DSL, zanim zostaną zablokowane na potrzeby utworzenia komponentu (wariant). ObiektyVariantBuilder
są tworzone na podstawie danych zawartych w obiektach DSL.Blokowanie DSL: DSL jest teraz zablokowany i nie można już wprowadzać zmian.
beforeVariants()
: ten wywołanie zwrotne może wpływać na to, które komponenty są tworzone, a także na niektóre ich właściwości za pomocąVariantBuilder
. Nadal umożliwia modyfikowanie procesu kompilacji i tworzonych artefaktów.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 poprzez blok 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. Możesz też zapoznać się z przykładami buildSrc
w naszym repozytorium przepisów na Gradle na GitHubie, aby dowiedzieć się, jak utworzyć wtyczkę w swoim 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ę 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 kolejnych fazach kompilacji. Możesz na przykład tworzyć nowe konfiguracje za pomocą programów lub zastępować właściwości. Pamiętaj jednak, że wszystkie wartości muszą być rozwiązywane w momencie konfiguracji, więc nie mogą zależeć od żadnych danych zewnętrznych.
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żyć do filtrowania komponentów biorących udział w wywoływaniu funkcji zwrotnej 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 AGPL, są już określone, więc nie można ich 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() })
}
Dodawanie wygenerowanych źródeł 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 zestawu źródłowego Java niestandardowy folder źródłowy 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 zestawu źródeł res
katalog z zasobami Androida wygenerowanymi na podstawie niestandardowego zadania. Ten proces jest podobny
w przypadku innych typów źródeł.
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.
Uzyskiwanie dostępu do artefaktów i ich modyfikowanie
Oprócz możliwości modyfikowania prostych właściwości obiektów Variant
interfejs AGP zawiera też mechanizm rozszerzenia, który umożliwia odczytywanie lub przekształcanie pośrednich i ostatecznych artefaktów tworzonych podczas kompilacji. Możesz na przykład odczytać ostateczną, scaloną zawartość pliku AndroidManifest.xml
w niestandardowym elemencie Task
, aby ją przeanalizować, lub zastąpić jego zawartość całkowicie 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 poznać:
Moc zbioru
Moc zbioru Artifact
reprezentuje liczbę wystąpień FileSystemLocation
lub liczbę plików albo katalogów typu artefaktu. Aby uzyskać informacje o mocy zbioru artefaktu, sprawdź jego klasę nadrzędną: artefakty z pojedynczym elementem FileSystemLocation
będą podklasą klasy 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ć obsługiwane operacje:
Transformable
: umożliwia użycieArtifact
jako wejścia dla funkcjiTask
, która wykonuje na nim dowolne przekształcenia i wyprowadza nową wersjęArtifact
.Appendable
: ma zastosowanie tylko do artefaktów, które są podklasamiArtifact.Multiple
. Oznacza to, że elementArtifact
może zostać dołączony do, co oznacza, że niestandardowy elementTask
może utworzyć nowe instancje tego typuArtifact
, które zostaną dodane do istniejącej listy.Replaceable
: ma zastosowanie tylko do artefaktów, które są podklasamiArtifact.Single
. Wymienny elementArtifact
można zastąpić całkowicie nowym wystąpieniem, wygenerowanym jako dane wyjściowe funkcjiTask
.
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ć dowolną liczbę operacji na artefaktach do potoku z poziomu wywołania zwrotnego onVariants()
, a AGP zadba o to, aby były one odpowiednio połączone, 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 zmienia jakiekolwiek dane wyjściowe przez ich dodanie, zastąpienie lub przekształcenie, następna operacja będzie traktować zaktualizowaną wersję tych artefaktów jako dane wejściowe i tak dalej.
Punktem wejścia do operacji rejestracji 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 obiekt TaskProvider
, aby uzyskać obiekt TaskBasedOperation
(1), a następnie użyć go do połączenia jego danych wejściowych i wyjściowych 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óry otrzymasz 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
jest SingleArtifact
i jest RegularFile
. Z tego względu musimy użyć metody wiredWithFiles
, która akceptuje pojedyncze odwołanie RegularFileProperty
dla danych wejściowych i pojedynczą wartość RegularFileProperty
dla danych wyjściowych. 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 z podręcznika systemu kompilacji Gradle:
- Tworzenie niestandardowych wtyczek Gradle
- Wdrażanie wtyczek Gradle
- Tworzenie niestandardowych typów zadań Gradle
- Leniwa konfiguracja
- Unikaj konfiguracji zadań