Interdependencias de herramientas y bibliotecas

Las dependencias de compilación son componentes externos necesarios para compilar tu proyecto de forma correcta. 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 se puede aplicar en cascada, y se actualizan 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ánticas sigue un formato major.minor.patch. Por ejemplo, en el número de versión 4.8.3, 4 es la versión de major, 8 es la versión de minor y 3 es el número de patch. Cuando cambia la parte major, la biblioteca puede tener cambios rotundos 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 tu proyecto y sus subproyectos incluyen durante la compilación
  • Herramientas: compiladores, complementos y SDKs que traducen tu fuente en una aplicación o biblioteca
Construir dependencias y sus relaciones
Figura 1. Entabla relaciones

Código fuente

Tu código fuente es código Kotlin o Java que escribes en tu aplicación o biblioteca. (Para obtener información detallada 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, agrega anotaciones como @Composable que deben procesarse por el complemento del compilador Kotlin para Compose. 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. Podría ser un archivo JAR de Java, una biblioteca de Android (AAR) o un subproyecto de la 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.

En ocasiones, 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.

El uso de algunas bibliotecas puede requerir el uso de un complemento de Gradle específico. Estos complementos auxiliares suelen instalar procesadores de símbolos de Kotlin u otros procesadores 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 el complemento del compilador de Compose para modificar las funciones anotadas a fin de 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 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 complemento que permite que el análisis externo y la generación de código se ejecuten directamente dentro del compilador, lo que permite acceder a la estructura del código analizado.

Complementos del compilador

Los complementos del compilador realizan análisis y 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

Java Development Kit, que contiene bibliotecas Java y ejecutables para compilar código fuente 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 configuraciones en la API de Gradle), lo que te permite especificar diferentes conjuntos de dependencias de bibliotecas para usar en distintas 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 las quieras cuando compiles y ejecutes tus pruebas de unidades. También puedes usar alcances para agregar procesadores de símbolos o anotaciones para analizar tu 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
}