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.
AGP zawiera punkty rozszerzeń, które umożliwiają kontrolowanie danych wejściowych kompilacji i rozszerzanie funkcjonalności za pomocą nowych kroków, które można zintegrować ze standardowymi zadaniami kompilacji. W poprzednich wersjach AGP oficjalne interfejsy API nie były wyraźnie oddzielone 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ślać stan interfejsów API:
- Wewnętrzny: nie przeznaczony do użytku publicznego.
- W fazie testów: dostępne do publicznego użytku, 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 Google Analytics 4 w koleistycznej dużej aktualizacji. 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 w 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ń. Aby dowiedzieć się więcej o podstawach Gradle w związku z AGP, przeczytaj artykuł Konfigurowanie procesu kompilacji. Informacje o ogólnej strukturze dostosowywania wtyczek Gradle znajdziesz w artykule Tworzenie niestandardowych wtyczek Gradle.
Słownik typów nieaktywnych w Gradle
Gradle udostępnia kilka typów, które działają „leniwie” lub pomagają odłożyć na późniejsze etapy kompilacji intensywne obliczenia lub tworzenie Task
. 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 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 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>
. Aby wygenerowaćTaskProvider
, użyj elementutasks.register()
, a nietasks.create()
, aby mieć pewność, że zadania są tworzone 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
.Task
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 wartość funkcji Provider
zostanie rozwiązana, np. gdy będzie to wymagane przez inną funkcję Task
.Provider
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ć zadania niestandardowe, które pobierają 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 AGP oferuje interfejs Variant API i dostęp do wyników jego zadań, czyli elementów budujących, które możesz odczytać i przekształcić. Więcej informacji znajdziesz w tym dokumencie w sekcji Variant API, Artifacts, and Tasks (Interfejs API wariantów, artefakty i zadania).
Etapy 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 fazach konfiguracji i wykonania. Więcej informacji o wszystkich fazach znajdziesz w przewodniku po cyklu życia kompilacji Gradle.
Etap konfiguracji
W trakcie konfiguracji oceniane są skrypty kompilacji wszystkich projektów wchodzących w skład kompilacji, 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.
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
W etapie wykonania są wykonywane żądane zadania i ich zadania zależne. W szczególności wykonywane są metody klasy Task
oznaczone jako @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 dostawców typu lazy w ten sposób uruchamia sekwencję wywołań map()
lub flatMap()
, które podążają za informacjami o zależnościach zadań zawartymi w dostawcy. Zadania są wykonywane cyklicznie, aby wygenerować wymagane 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 utworzonych przez kompilację, takich jak pliki klasy, scalony plik manifestu lub pliki APK/AAB.
Proces kompilacji aplikacji na Androida i punkty rozszerzenia
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
ani zgadywać ich nazw, a także nie dodawaj bezpośrednio do tych obiektów wywołań zwrotnych ani zależności.Task
Task
AGP wykonuje te czynności, aby utworzyć i wykonać instancje Task
, które z kolei generują artefakty kompilacji. Główne kroki związane z tworzeniem obiektu Variant
są poprzedzone wywołaniami zwrotnymi, które umożliwiają wprowadzanie zmian w określonych obiektach utworzonych w ramach kompilacji. Pamiętaj, że wszystkie wywołania zwrotne są wykonywane w fazie konfiguracji (opisanej na tej stronie) i muszą być szybkie, a każda skomplikowana operacja musi zostać odroczona do właściwych instancji Task
w fazie wykonania.
- 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
. W tej fazie są też rejestrowane wywołania zwrotne interfejsu Variant API opisane w następnych 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()
: 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 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 przez nie 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
, które są niezbędne do wykonania kompilacji.
AGP wprowadza parametr AndroidComponentsExtension
, który umożliwia rejestrowanie wywołań zwrotnych dla zdarzeń 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)
W tym wywołaniu zwrotnym możesz uzyskiwać dostęp do obiektów DSL i je modyfikować. Zostały one utworzone przez zanalizowanie 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 wykonywania tej funkcji wywołania zwrotnego obiekty DSL nie są już przydatne i nie należy już ich trzymać ani modyfikować.
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()
w obiekcie 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
będą przetwarzane tylko podczas wykonywania zadań AGP, więc możesz je bezpiecznie podłączyć do dostawców z własnych niestandardowych zadań, które wykonają wszystkie niezbędne obliczenia, w tym odczyt z zewnętrznych danych wejściowych, takich jak pliki czy 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 zbioru źródeł Javy niestandardowy folder ${variant.name}
. Następnie narzędzia Androida przetwarzają ten folder.
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
Aby dowiedzieć się więcej, zapoznaj się z przepisem addJavaSource.
Ten fragment kodu pokazuje, jak dodać do zestawu źródeł res
katalog z zasobami Androida wygenerowanymi na podstawie niestandardowego zadania. 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ę wystąpień FileSystemLocation
lub liczbę plików albo 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 artefakt każdy artefakt obsługuje operację get()
(lub getAll()
), która zwraca Provider
z ostateczną wersją artefaktu (po zakończeniu wszystkich operacji).
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.
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, którą należy wybrać, zależy od mocy zbioru i typu FileSystemLocation
zaimplementowanego przez 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
jest SingleArtifact
i jest 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 z podręcznika systemu kompilacji Gradle:
- Tworzenie niestandardowych wtyczek Gradle
- Implementowanie wtyczek Gradle
- Tworzenie niestandardowych typów zadań Gradle
- Konfiguracja leniwego ładowania
- Unikanie konfiguracji zadań