El complemento de Android para Gradle (AGP) es el sistema de compilación oficial de las aplicaciones para Android. Incluye compatibilidad para compilar muchos tipos diferentes de fuentes y vincularlas en una aplicación que puedes ejecutar en un dispositivo físico con Android o un emulador.
AGP contiene puntos de extensión para que los complementos controlen las entradas de compilación y extiendan su funcionalidad mediante pasos nuevos que se pueden integrar con tareas de compilación estándar. Las versiones anteriores del AGP no tenían APIs oficiales claramente separadas de las implementaciones internas. A partir de la versión 7.0, el AGP tiene un conjunto de APIs oficiales y estables en las que puedes confiar.
Ciclo de vida de las API de AGP
El AGP sigue el ciclo de vida de las funciones de Gradle para designar el estado de sus APIs:
- Interna: No está diseñada para uso público.
- En incubación: Están disponibles para uso público, pero no son definitivas, lo que significa que podrían no ser retrocompatibles en la versión final.
- Pública: Disponible para uso público y estable.
- Obsoleta: Ya no es compatible y se reemplazó con API nuevas.
Política de baja
AGP está avanzando con la baja de las API anteriores y su reemplazo con API nuevas y estables, además de un nuevo lenguaje específico de dominio (DSL). Esta evolución abarcará varias versiones del AGP. Obtén más información al respecto en el cronograma de migración del DSL y la API de AGP.
Cuando las API de AGP dejen de estar disponibles para esta migración o en otros casos, seguirán estando disponibles en la versión principal actual, pero generarán advertencias. Las API obsoletas se quitarán por completo de AGP en la versión principal posterior. Por ejemplo, si una API deja de estar disponible en AGP 7.0, estará disponible en esa versión y generará advertencias. Esa API ya no estará disponible en AGP 8.0.
Para ver ejemplos de APIs nuevas que se usan en personalizaciones de compilación comunes, consulta las recetas del complemento de Android para Gradle. Proporcionan ejemplos de personalizaciones de compilación comunes. Puedes encontrar detalles adicionales sobre las nuevas APIs en nuestra documentación de referencia.
Compila con el artefacto de la API de AGP
Para escribir un complemento de Gradle personalizado o una lógica de compilación (como en el directorio buildSrc, un módulo de complemento de convención o un proyecto de complemento independiente) que extienda el AGP, compila con el artefacto gradle-api del AGP en lugar del artefacto de implementación del complemento completo.
¿Por qué compilar con el artefacto gradle-api?
El AGP publica dos artefactos principales:
com.android.tools.build:gradle-api: Contiene APIs oficiales del AGP, incluidas las APIs estables (comoAndroidComponentsExtension,Varianty las interfaces de DSL públicas), las APIs en fase de incubación (marcadas como@Incubating) y las APIs obsoletas (marcadas como@Deprecated).com.android.tools.build:gradle: Contiene la implementación completa del entorno de ejecución del AGP, incluidas las clases internas, las tareas de compilación y las integraciones del compilador.
La compilación con el artefacto gradle-api proporciona varios beneficios clave:
- Evita las APIs internas: Garantiza que el código de tu complemento solo acceda a las APIs oficiales. Esto evita dependencias accidentales en clases de implementación interna (
com.android.build.gradle.internal.*) que pueden cambiar o quitarse en las versiones del AGP sin previo aviso. - Compilaciones más rápidas y menor espacio de almacenamiento: El artefacto
gradle-apitiene un árbol de dependencias mucho más pequeño que el artefactogradlecompleto. Esto reduce los tamaños de descarga, evita la contaminación de la ruta de clase y acelera la compilación de tu lógica de compilación. - Aislamiento del entorno de ejecución: Los complementos personalizados solo requieren definiciones de la API durante la compilación. En el entorno de ejecución, la implementación completa del AGP la proporciona la compilación de Android cuando se aplica el complemento de la aplicación para Android o de la biblioteca.
Agrega la dependencia
Agrega el artefacto gradle-api como una dependencia en el archivo de compilación de tu proyecto de complemento o en el directorio buildSrc. El artefacto gradle-api se publica en el
repositorio de Maven de Google. Para resolver el artefacto, asegúrate de que tu compilación incluya el repositorio google(). Por ejemplo, configúralo en el bloque dependencyResolutionManagement.repositories del archivo settings.gradle o settings.gradle.kts, o en el bloque repositories del archivo de compilación de tu complemento o del archivo de compilación del directorio buildSrc.
Con un catálogo de versiones
Si tu proyecto usa un catálogo de versiones, define la dependencia gradle-api en el archivo gradle/libs.versions.toml:
[versions]
androidGradlePlugin = "9.5.0"
[libraries]
android-gradle-plugin-api = { group = "com.android.tools.build", name = "gradle-api", version.ref = "androidGradlePlugin" }
El alias del catálogo android-gradle-plugin-api genera el descriptor de acceso con seguridad de tipos libs.android.gradle.plugin.api.
Luego, agrega libs.android.gradle.plugin.api al bloque dependencies del archivo de compilación de tu complemento:
Kotlin
dependencies { compileOnly(libs.android.gradle.plugin.api) }
Groovy
dependencies { compileOnly libs.android.gradle.plugin.api }
Sin un catálogo de versiones
Si tu proyecto no usa un catálogo de versiones, declara la dependencia directamente en el archivo de compilación del complemento:
Kotlin
dependencies { compileOnly("com.android.tools.build:gradle-api:9.5.0") }
Groovy
dependencies { compileOnly 'com.android.tools.build:gradle-api:9.5.0' }
Usa la opción de configuración compileOnly como predeterminada para los complementos independientes destinados a la publicación. El proyecto de consumo aplica el AGP y proporciona
sus clases de entorno de ejecución en la ruta de clase de buildscript. El uso de la configuración compileOnly
impide que el complemento publicado filtre una dependencia del entorno de ejecución
en una versión específica del AGP y evita conflictos de versiones para los consumidores. Si desarrollas una lógica de compilación interna, como complementos en el directorio buildSrc o complementos de convenciones en compilaciones compuestas, usa la opción de configuración implementation en su lugar. Estos complementos se ejecutan dentro de la compilación y requieren AGP en su ruta de clase de entorno de ejecución.
Conceptos básicos de compilación de Gradle
En esta guía, no se abarca todo el sistema de compilación de Gradle. Sin embargo, sí se incluye el conjunto mínimo de conceptos necesarios para ayudarte a integrar nuestras API, además de vínculos a la documentación principal de Gradle para consultas adicionales.
Ten en cuenta que se requieren conocimientos básicos sobre el funcionamiento de Gradle, como configuración de proyectos, edición archivos de compilación, uso de complementos y ejecución de tareas. Para conocer los conceptos básicos de Gradle con respecto al AGP, te recomendamos que leas Cómo configurar tu compilación. Para obtener información sobre el framework general para personalizar los complementos de Gradle, consulta Cómo desarrollar complementos de Gradle personalizados.
Glosario de tipos diferidos de Gradle
Gradle ofrece varios tipos que se comportan de forma "diferida" o ayudan a posponer los cálculos pesados o la creación de Task para fases posteriores de la compilación. Estos tipos son la base de muchas APIs de Gradle y AGP. La siguiente lista incluye los principales tipos de Gradle involucrados en la ejecución diferida y sus métodos clave.
Provider<T>Proporciona un valor de tipo
T(donde "T" significa cualquier tipo), que se puede leer durante la fase de ejecución conget()o transformarse en unProvider<S>nuevo (donde "S" significa algún otro tipo) con los métodosmap(),flatMap()yzip(). Ten en cuenta que nunca se debe llamar aget()durante la fase de configuración.
map(): Acepta una lambda y produce unProviderde tipoS,Provider<S>. El argumento lambda paramap()toma el valorTy produce el valorS. La expresión lambda no se ejecuta de inmediato, sino que su ejecución se aplaza hasta el momento en que se llama aget()en elProvider<S>resultante, lo que hace que toda la cadena sea diferida.flatMap(): También acepta una lambda y produceProvider<S>, pero la lambda toma un valorTy produceProvider<S>(en lugar de producir el valorSdirectamente). UsaflatMap()cuando no se pueda determinar S en el momento de la configuración y solo puedas obtenerProvider<S>. En la práctica, si usastemap()y obtuviste un tipo de resultadoProvider<Provider<S>>, es probable que debas usarflatMap()en su lugar.zip(): Te permite combinar dos instancias deProviderpara producir una nueva instancia deProvider, con un valor calculado a través de una función que combina los valores de las dos instancias deProviderde entrada.
Property<T>Implementa
Provider<T>, por lo que también proporciona un valor de tipoT. A diferencia deProvider<T>, que es de solo lectura, también puedes establecer un valor paraProperty<T>. Existen dos maneras de hacerlo:
- Establecer un valor de tipo
Tdirectamente cuando esté disponible, sin la necesidad de realizar cálculos diferidos - Configurar otro
Provider<T>como la fuente del valor de laProperty<T>En este caso, el valorTse materializa solo cuando se llama aProperty.get().
TaskProvider- Implementa
Provider<Task>. Para generar unTaskProvider, usatasks.register()y notasks.create(), para asegurarte de que las tareas solo se creen de forma diferida cuando se necesiten. Puedes usarflatMap()para acceder a los resultados de unTaskantes de que se cree elTask, lo que puede ser útil si deseas usar los resultados como entradas para otras instancias deTask.
Los proveedores y sus métodos de transformación son esenciales para configurar entradas y salidas de tareas de manera diferida, es decir, sin necesidad de crear todas las tareas por adelantado y resolver los valores.
Los proveedores también tienen información sobre la dependencia de las tareas. Cuando creas un Provider
transformando un resultado de Task, ese Task se convierte en una dependencia implícita del
Provider y se creará y ejecutará cada vez que se resuelva el valor del Provider,
como cuando otro Task lo requiera.
A continuación, se muestra un ejemplo para registrar dos tareas, GitVersionTask y ManifestProducerTask, y diferir la creación de las instancias de Task hasta que sean obligatorias. El valor de entrada de ManifestProducerTask se establece en un Provider que se obtuvo del resultado de GitVersionTask, por lo que ManifestProducerTask depende de manera implícita de 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))
}
Estas dos tareas solo se ejecutarán si se solicitan de explícitamente. Esto puede suceder como parte de una invocación de Gradle, por ejemplo, si ejecutas ./gradlew
debugManifestProducer o si el resultado de ManifestProducerTask está conectado a alguna otra tarea y se requiere su valor.
Si bien escribirás tareas personalizadas que consumen entradas, producen salidas o ambas, el AGP no ofrece acceso público a sus propias tareas de forma directa. Son un detalle de implementación sujeto a cambios de versión a versión. En su lugar, el AGP ofrece la API de Variant y acceso al resultado de sus tareas o artefactos de compilación, que puedes leer y transformar. Consulta API de variantes, artefactos y tareas en este documento para obtener más información.
Fases de compilación de Gradle
La compilación de un proyecto es inherentemente un proceso complicado que requiere muchos recursos. Sin embargo, hay varias funciones, como la elusión de la configuración de tareas, las verificaciones actualizadas y la función de almacenamiento en caché de configuración, que ayudan a minimizar el tiempo invertido en cálculos reproducibles o innecesarios.
Para aplicar algunas de estas optimizaciones, las secuencias de comandos y los complementos de Gradle deben obedecer reglas estrictas durante cada una de las distintas fases de compilación de Gradle: inicialización, configuración y ejecución. En esta guía, nos enfocaremos en las fases de configuración y ejecución. Puedes encontrar más información sobre todas las fases en la guía del ciclo de vida de compilación de Gradle.
Fase de configuración
Durante la fase de configuración, se evalúan las secuencias de comandos de compilación de todos los proyectos que forman parte de la compilación, se aplican los complementos y se resuelven las dependencias de compilación. Esta fase debe usarse para configurar la compilación mediante objetos DSL y para registrar tareas y sus entradas de manera diferida.
Debido a que la fase de configuración se ejecuta siempre, independientemente de la tarea que se solicita para ejecución, es muy importante que sea eficiente y evitar que los cálculos dependan de entradas que no sean las secuencias de comandos de compilación.
Es decir, no debes ejecutar programas externos ni leer desde la red ni realizar cálculos largos que se puedan diferir a la fase de ejecución como instancias de Task adecuadas.
Fase de ejecución
En la fase de ejecución, se ejecutan las tareas solicitadas y las tareas dependientes. En concreto, se ejecutan los métodos de clase de Task marcados con @TaskAction. Durante la ejecución de las tareas, si llamas a Provider<T>.get(), puedes leer las entradas (como los archivos) y resolver los proveedores diferidos. Resolver proveedores diferidos de esta manera inicia una secuencia de llamadas map() o flatMap() que siguen la información de dependencia de la tarea contenida en el proveedor. Las tareas se ejecutan de forma diferida para materializar los valores requeridos.
API de variantes, artefactos y tareas
La API de Variant es un mecanismo de extensión del complemento de Android para Gradle que te permite manipular las diversas opciones, que normalmente se configuran con el DSL en los archivos de configuración de compilación, que influyen en la compilación de Android. La API de Variant también te brinda acceso a artefactos intermedios y finales que se crean con la compilación, como archivos de clase, el manifiesto combinado o archivos APK o AAB.
Flujo de compilación y puntos de extensión de Android
Cuando interactúes con el AGP, usa puntos de extensión creados especialmente en lugar de registrar las devoluciones de llamada de ciclo de vida típicas de Gradle (como afterEvaluate()) o configurar dependencias de Task explícitas. Las tareas que crea el AGP se consideran detalles de implementación y no se exponen como una API pública. Evita obtener instancias de los objetos Task o adivinar los nombres de Task y agregar devoluciones de llamada o dependencias a esos objetos de Task directamente.
AGP completa los siguientes pasos para crear y ejecutar sus instancias de Task, que, a su vez, producen los artefactos de compilación. Después de los pasos principales que se incluyen en la creación de objetos Variant, siguen las devoluciones de llamada que te permiten realizar cambios en ciertos objetos creados como parte de una compilación. Es importante tener en cuenta que todas las devoluciones de llamada ocurren durante la fase de configuración (que se describe en esta página) y que deben ejecutarse rápido, de forma tal que se difiera cualquier trabajo complicado en las instancias de Task adecuadas durante la fase de ejecución.
Análisis de DSL: Aquí se evalúan las secuencias de comandos de compilación y se crean y configuran las distintas propiedades de los objetos DSL de Android del bloque
android. Las devoluciones de llamada de la API de Variant que se describen en las siguientes secciones también se registran durante esta fase.finalizeDsl(): Es la devolución de llamada que te permite cambiar los objetos DSL antes de que se bloqueen para la creación de componentes (variantes). Los objetosVariantBuilderse crean en función de los datos que contienen los objetos DSL.
Bloqueo de DSL: DSL está bloqueado y ya no es posible hacer cambios.
beforeVariants(): Esta devolución de llamada puede influir en los componentes que se crean y en algunas de sus propiedades a través deVariantBuilder. Aún permite realizar modificaciones en el flujo de compilación y los artefactos que se producen.
Creación de variantes: Se finaliza la lista de componentes y artefactos que se crearán, y no se puede cambiar.
onVariants(): En esta devolución de llamada, obtienes acceso a los objetosVariantcreados y puedes establecer valores o proveedores para los valores dePropertyque contienen, que se calcularán de forma diferida.
Bloqueo de variantes: Los objetos de variantes ahora están bloqueados y ya no es posible realizar cambios.
Tareas creadas: Los objetos
Varianty sus valoresPropertyse usan para crear las instancias deTaskque son necesarias a fin de ejecutar la compilación.
El AGP presenta un AndroidComponentsExtension que te permite registrar devoluciones de llamada para finalizeDsl(), beforeVariants() y onVariants().
La extensión está disponible en las secuencias de comandos de compilación a través del bloque androidComponents:
// This is used only for configuring the Android build through DSL.
android { ... }
// The androidComponents block is separate from the DSL.
androidComponents {
finalizeDsl { extension ->
...
}
}
Sin embargo, te recomendamos que mantengas las secuencias de comandos de compilación solo para la configuración declarativa con el DSL del bloque de Android y que muevas cualquier lógica imperativa personalizada al directorio buildSrc o a los complementos externos. También puedes consultar las muestras de buildSrc en nuestro repositorio de GitHub de recetas de Gradle para aprender a crear un complemento en tu proyecto. Asegúrate de que tu
complemento se compile con el artefacto gradle-api
en tu archivo de compilación. Este es un ejemplo de cómo registrar las devoluciones de llamada desde el código del complemento:
abstract class ExamplePlugin: Plugin<Project> {
override fun apply(project: Project) {
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.finalizeDsl { extension ->
...
}
}
}
En las siguientes secciones, se describen las devoluciones de llamada disponibles y el tipo de casos de uso que tu complemento puede admitir en cada una de ellas:
finalizeDsl(callback: (DslExtensionT) -> Unit)
En esta devolución de llamada, puedes acceder a los objetos DSL que se crearon y modificarlos mediante el análisis de la información del bloque android en los archivos de compilación.
Estos objetos DSL se usarán para inicializar y configurar variantes en las fases posteriores de la compilación. Por ejemplo, puedes crear configuraciones nuevas de manera programática o anular propiedades. Sin embargo, ten en cuenta que todos los valores deben resolverse en el momento de la configuración, por lo que no deben depender de las entradas externas.
Una vez que se termina de ejecutar esta devolución de llamada, los objetos DSL ya no son útiles y ya no debes tener referencias a ellos ni modificar sus valores.
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()
En esta etapa de la compilación, obtendrás acceso a objetos VariantBuilder, que determinan las variantes que se crearán y sus propiedades. Por ejemplo, puedes inhabilitar de manera programática determinadas variantes y sus pruebas o cambiar el valor de una propiedad (por ejemplo, minSdk) solo para una variante seleccionada. De manera similar a finalizeDsl(), todos los valores que proporcionas deben resolverse en el momento de la configuración y no depender de entradas externas. Los objetos VariantBuilder no deben modificarse una vez que termina la ejecución de la devolución de llamada de beforeVariants().
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
De manera opcional, la devolución de llamada beforeVariants() toma un objeto VariantSelector, que puedes obtener a través del método selector() en androidComponentsExtension. Puedes usarlo para filtrar los componentes que participan en la invocación de devolución de llamada según su nombre, tipo de compilación o variante de producto.
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
Antes de llamar a onVariants(), ya se decidieron todos los artefactos que creará AGP, por lo que ya no puedes inhabilitarlos. Sin embargo, puedes modificar algunos de los valores que se usan para las tareas configurándolos para los atributos Property en los objetos Variant. Debido a que los valores Property solo se resolverán cuando se ejecuten las tareas del AGP, puedes vincularlos de forma segura con los proveedores de tus propias tareas personalizadas que realizarán cualquier cálculo requerido, incluida la lectura desde entradas externas como archivos o la red.
// 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() })
}
Cómo aportar fuentes generadas a la compilación
Tu complemento puede aportar algunos tipos de fuentes generadas, como las siguientes:
- Código de la aplicación en el directorio
java - Recursos de Android en el directorio
res - Recursos de Java en el directorio
resources - Recursos de Android en el directorio
assets
Para obtener la lista completa de fuentes que puedes agregar, consulta la API de Sources.
En este fragmento de código, se muestra cómo agregar una carpeta personalizada de fuentes llamada ${variant.name} al conjunto de orígenes de Java con la función addStaticSourceDirectory(). La cadena de herramientas de Android luego procesa esta carpeta.
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
Consulta la receta de JavaSource para obtener más detalles.
En este fragmento de código, se muestra cómo agregar un directorio con recursos de Android generados a partir de una tarea personalizada al conjunto de orígenes res. El proceso es similar para otros tipos de fuentes.
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.
...
}
}
Consulta la receta de addCustomAsset para obtener más detalles.
Acceso y modificación de artefactos
Además de permitirte modificar las propiedades básicas de los objetos Variant, el AGP también contiene un mecanismo de extensión que te permite leer o transformar artefactos intermedios y finales producidos durante la compilación. Por ejemplo, puedes leer el contenido combinado final del archivo AndroidManifest.xml en una Task personalizada para analizarlo o puedes reemplazar todo su contenido por el de un archivo de manifiesto generado por tu Task personalizada.
Puedes encontrar la lista de artefactos que se admiten actualmente en la documentación de referencia de la clase Artifact. Cada tipo de artefacto tiene
ciertas propiedades que es útil conocer:
Cardinalidad
La cardinalidad de un Artifact representa su cantidad de
instancias de FileSystemLocation o la
cantidad de archivos o directorios del tipo de artefacto. Puedes obtener información
sobre la cardinalidad de un artefacto si verificas su clase superior: Los artefactos
con un solo FileSystemLocation serán una subclase de
Artifact.Single; los artefactos con varias
instancias de FileSystemLocation serán una subclase de
Artifact.Multiple.
Tipo FileSystemLocation
Puedes verificar si un Artifact representa archivos o directorios observando su
tipo FileSystemLocation parametrizado, que puede ser un
RegularFile o un
Directory.
Operaciones admitidas
Cada clase de Artifact puede implementar cualquiera de las siguientes interfaces para indicar el tipo de operaciones que admite:
Transformable: Permite que unArtifactse use como entrada para unTaskque realiza transformaciones arbitrarias en él y genera una versión nueva delArtifact.Appendable: Se aplica solo a los artefactos que son subclases deArtifact.Multiple. Significa que se puede agregar unArtifact, es decir, unTaskpersonalizado puede crear instancias nuevas de este tipo deArtifactque se agregarán a la lista existente.Replaceable: Se aplica solo a los artefactos que son subclases deArtifact.Single. UnArtifactreemplazable se puede sustituir por una instancia completamente nueva, producida como resultado de unTask.
Además de las tres operaciones de modificación de artefactos, cada artefacto admite
una operación get() (o getAll()), que
devuelve un Provider con la versión final del artefacto (después de que finalizan
todas las operaciones en él).
Varios complementos pueden agregar cualquier cantidad de operaciones en artefactos a la canalización desde la devolución de llamada onVariants(), y el AGP se asegurará de que estén encadenados correctamente para que todas las tareas se ejecuten en el momento adecuado y los artefactos se produzcan y actualicen de forma correcta. Esto significa que, cuando una operación cambia cualquier resultado agregándolo, reemplazándolo o transformándolo, cada operación posterior verá la versión actualizada
de estos artefactos como entradas.
El punto de entrada para registrar operaciones es la clase Artifacts. En el siguiente fragmento de código, se muestra cómo puedes obtener acceso a una instancia de Artifacts desde una propiedad en el objeto Variant en la devolución de llamada onVariants().
Luego, puedes pasar tu TaskProvider personalizado para obtener un objeto TaskBasedOperation (1) y usarlo para conectar sus entradas y salidas con uno de los métodos wiredWith* (2).
El método exacto que debes elegir depende de la cardinalidad y del tipo de FileSystemLocation que implementa el Artifact que deseas transformar.
Por último, pasas el tipo Artifact a un método que representa la operación elegida en el objeto *OperationRequest que obtienes a cambio, por ejemplo, toAppendTo(), toTransform() o 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)
}
En este ejemplo, MERGED_MANIFEST es un SingleArtifact y es un RegularFile. Por ese motivo, debemos usar el método wiredWithFiles, que acepta una sola referencia RegularFileProperty para la entrada y un solo RegularFileProperty para la salida. Existen otros métodos wiredWith* en la clase TaskBasedOperation que funcionarán para otras combinaciones de cardinalidad de Artifact y tipos de FileSystemLocation.
Para obtener más información a fin de extender el AGP, te recomendamos que leas las siguientes secciones del manual del sistema de compilación de Gradle:
- Developing Custom Gradle Plugins (Cómo desarrollar complementos personalizados de Gradle)
- Implementing Gradle plugins (Cómo implementar complementos de Gradle)
- Developing Custom Gradle Task Types (Cómo desarrollar tipos de tareas personalizadas de Gradle)
- Lazy Configuration (Configuración diferida)
- Task Configuration Avoidance (Elusión de configuración de tareas)