Interdependencias de herramientas y bibliotecas

Las dependencias de compilación son componentes externos necesarios para compilar correctamente tu proyecto. Una compilación puede depender de bibliotecas, complementos y subproyectos, el SDK de Android, herramientas como los compiladores de Kotlin y Java, entornos de desarrollo como Android Studio y Gradle.

Cada dependencia puede requerir otras dependencias. Las llamamos dependencias transitivas y pueden aumentar rápidamente las dependencias generales que usa tu aplicación. Cuando quieras actualizar una dependencia, ya sea una biblioteca, una herramienta o el SDK de Android, esa actualización puede aplicarse en cascada y actualizar muchas otras dependencias.

A menudo, esto no causará problemas, ya que muchas bibliotecas siguen un esquema conocido como control de versiones semántico. Estas bibliotecas restringen los tipos de cambios que realizan para proporcionar compatibilidad con sus versiones anteriores.

El control de versiones semántico sigue un formato major.minor.patch. Por ejemplo, en el número de versión 4.8.3, 4 es la versión major, 8 es la versión minor y 3 es el número patch. Cuando cambia la parte major, es posible que la biblioteca tenga cambios fundamentales en la API o el comportamiento. Esto puede afectar el comportamiento de tu compilación o aplicación.

Cuando cambian las partes minor (funciones nuevas) o patch (corrección de errores), los desarrolladores de la biblioteca te indican que la biblioteca aún es compatible y no debería afectar a tu aplicación.

Es importante estar atento a estos cambios, y varias herramientas de actualización de dependencias pueden ayudarte.

Relaciones en tu compilación

Las compilaciones de Android contienen relaciones entre lo siguiente:

  • Código fuente: El código y los recursos sobre los que tienes control
  • Dependencias de bibliotecas: bibliotecas o módulos externos que el proyecto y los subproyectos incluyen cuando se compilan.
  • Herramientas: Compiladores, complementos y SDKs que traducen el código fuente en una aplicación o biblioteca
Cómo compilar dependencias y sus relaciones
Figura 1. Entabla relaciones

Código fuente

El código fuente es el código Kotlin o Java que escribes en tu aplicación o biblioteca. (Para obtener detalles sobre el uso de C++, consulta NDK de Android).

El código fuente depende de las bibliotecas (incluidas las bibliotecas de tiempo de ejecución de Kotlin y Java) y del SDK de Android, y requiere su compilador Kotlin o Java correspondiente.

Algunos códigos fuente incluyen anotaciones que requieren procesamiento adicional. Por ejemplo, si escribes código de Jetpack Compose, agregas anotaciones como @Composable que el complemento del compilador de Kotlin de Compose debe procesar. Un procesador de símbolos de Kotlin (KSP) o herramientas de procesamiento de anotaciones independientes pueden procesar otras anotaciones.

Dependencias de bibliotecas

Las bibliotecas contienen códigos de bytes que se extraen como parte de tu aplicación. Puede ser un archivo JAR de Java, una biblioteca de Android (AAR) o un subproyecto en tu compilación. Muchas bibliotecas siguen el control de versiones semántico, que puede ayudarte a comprender cuándo siguen siendo compatibles (o no) cuando se actualizan.

Las bibliotecas pueden depender de otras bibliotecas para su reutilización, lo que se denomina dependencia transitiva. Esto reduce las dependencias que debes administrar de forma explícita. Especificas las dependencias que usas directamente, y Gradle las extrae junto con esas dependencias transitivas. Ten en cuenta que, a medida que actualizas tus dependencias directas, es posible que se actualicen esas dependencias transitivas.

A veces, una biblioteca puede requerir versiones mínimas del SDK de Android en el tiempo de ejecución (minSdk) o en el tiempo de compilación (compileSdk). Esto es necesario cuando una biblioteca usa funciones incluidas en el SDK de Android o sus APIs de JDK proporcionadas. El minSdk efectivo de tu aplicación es el minSdk más alto que solicita tu aplicación y todas sus dependencias de bibliotecas directas y transitivas.

Es posible que el uso de algunas bibliotecas requiera el uso de un complemento de Gradle específico. Estos complementos auxiliares a menudo instalan procesadores de símbolos de Kotlin o algún otro procesador de anotaciones que generan código o modifican la compilación de tu fuente para admitir el uso de las funciones de la biblioteca. Por ejemplo, Jetpack Room incluye anotaciones y un KSP que los transforma en código generado para recuperar y modificar datos en una base de datos. Jetpack Compose requiere que el complemento del compilador de Compose modifique las funciones con anotaciones para administrar cómo y cuándo se vuelve a ejecutar esa función.

Herramientas

Gradle

Gradle es la herramienta de compilación que lee tus archivos de compilación y genera tu aplicación o biblioteca. También expone una API para que los complementos amplíen sus capacidades. Gradle ejecuta varios procesos en una o más máquinas virtuales de Java, y sus complementos de Java llaman a las herramientas de Java dentro del JDK.

Complementos de Gradle

Los complementos de Gradle extienden Gradle definiendo tareas y configuraciones nuevas. Aplicar un complemento a tu compilación habilita capacidades de compilación específicas, configuradas como datos en tus secuencias de comandos de compilación. Para las compilaciones de Android, el complemento de Gradle más importante es el complemento de Android para Gradle (AGP).

Compiladores

El compilador de Kotlin o Java transforma tu código fuente en código de bytes ejecutable. El compilador de Kotlin expone una API de complementos que permite que el análisis externo y la generación de código se ejecuten directamente dentro del compilador y accedan a la estructura de código analizada.

Complementos del compilador

Los complementos del compilador realizan el análisis y la generación de código dentro del compilador de Kotlin mientras este analiza tu código y se instalan cuando aplicas sus complementos de Gradle a la compilación.

SDK de Android

El SDK de Android contiene las APIs de Java y la plataforma de Android para una versión específica de Android y sus herramientas correspondientes. Estas herramientas te ayudan a administrar el SDK, compilar tus aplicaciones y comunicarte con dispositivos Android y emularlos.

Cada versión del SDK de Android proporciona APIs de Java específicas a las que puede acceder tu código fuente y compatibilidad con la expansión de sintaxis para usar esas APIs en versiones anteriores de Android.

JDK

El kit de desarrollo de Java, que contiene bibliotecas y ejecutables de Java para compilar fuentes de Java y ejecutar aplicaciones de Java. Hay varios JDK en juego en una compilación de Android. Para obtener más información, consulta Versiones de Java en compilaciones de Android.

Permisos de Gradle

Gradle agrupa las dependencias de bibliotecas en diferentes alcances (llamados parámetros de configuración en la API de Gradle), lo que te permite especificar diferentes conjuntos de dependencias de bibliotecas que se usarán en diferentes partes de tu compilación. Por ejemplo, es probable que no quieras incluir bibliotecas de prueba, como JUnit, en tu aplicación o biblioteca publicada, pero sí cuando compilas y ejecutas tus pruebas de unidades. También puedes usar alcances para agregar procesadores de símbolos o anotaciones para analizar el código.

Por ejemplo, AGP define los alcances implementation y api, tu forma de especificar si una dependencia debe exponerse a los usuarios de tu subproyecto. Consulta Cómo configurar dependencias para obtener descripciones de estos y otros alcances que se usan en una compilación de Android.

Agrega dependencias de bibliotecas en el bloque dependencies de tus archivos de compilación, ya sea como cadenas group:artifact:version:

Kotlin

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation("com.example:library1:1.2.3")
    api("com.example:library2:1.1.1")
}

Groovy

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation 'com.example:library1:1.2.3'
    api 'com.example:library2:1.1.1'
}

o en un Catálogo de versiones:

# Version catalog - gradle/libs.versions.toml
[versions]
exampleLib = "1.2.3"
examplePlugin = "2.3.4"

[libraries]
example-library = { group = "com.example", name = "library", version.ref = "exampleLib" }

[plugins]
example-plugin = { id = "com.example.plugin", version.ref = "examplePlugin" }

y especifica las variables generadas en tus archivos de compilación:

Kotlin

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation(libs.example.library)
}

Groovy

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation libs.example.library
}