Tus archivos de compilación especifican tus dependencias directas, pero cada una de ellas puede requerir otras. Estas dependencias transitivas aumentan rápidamente el gráfico de dependencias general, a menudo con versiones en conflicto.
Cuando cambian las partes minor
(nuevas funciones) o patch
(corrección de errores), es probable que la biblioteca siga siendo compatible y sea menos probable que afecte a tu aplicación.
Por ejemplo, supongamos que tu aplicación depende de la biblioteca A y la biblioteca B, que, a su vez, dependen de diferentes versiones de la biblioteca C.
En este caso, Gradle elige la versión más reciente de la biblioteca C de forma predeterminada, lo que puede causar problemas de compilación o tiempo de ejecución. En este ejemplo, la biblioteca C se resuelve a la versión 2.1.1, pero ten en cuenta que la biblioteca A solicitó la biblioteca C 1.0.3. La mayor parte del número de versión cambió, lo que indica cambios incompatibles, como funciones o tipos quitados. Esto podría provocar que fallaran las llamadas realizadas desde la biblioteca A.
Tu app puede tener dependencias directas que también sean dependencias transitivas.
En un caso como este, las dependencias transitivas más recientes pueden anular la versión que pides directamente en tu app.
Gradle analiza todas las versiones candidatas de todas las dependencias del gráfico para determinar la versión más reciente de cada una. Puedes usar tareas básicas de Gradle y herramientas más avanzadas para determinar qué versiones de cada dependencia resolvió Gradle. Comparar los cambios en esta resolución es clave para comprender y mitigar los riesgos de la actualización.
Por ejemplo, puedes usar la tarea dependencies
de Gradle ejecutando ./gradlew
app:dependencies
para mostrar un árbol de todas las dependencias que usa el módulo de tu app. Si lo ejecutas en una aplicación que usa las bibliotecas,
como se muestra en la Figura 2,
1: releaseRuntimeClasspath - Runtime classpath of /release.
2: +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0
3: | +--- ... (omitted for brevity) ...
4: +--- com.sample:library.a:1.2.3
5: | +--- com.sample:library.c:2.1.1
6: | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
7: | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
8: +--- com.sample:library.c:1.4.1 -> 2.1.1 (*)
En esta parte del informe, se muestran algunas de las dependencias resueltas para la configuración de releaseRuntimeClasspath
.
Cada vez que veas ->
en tu informe de dependencias, significa que un solicitante (tu aplicación o otra biblioteca) usa una versión de esa dependencia que no espera. En muchos casos, esto no causa ningún problema, ya que la mayoría de las bibliotecas están escritas para la retrocompatibilidad. Sin embargo, es posible que algunas bibliotecas realicen cambios incompatibles, y este informe puede ayudarte a determinar de dónde provienen los problemas nuevos con el comportamiento de tu aplicación.
Puedes encontrar más información sobre el uso de los informes de dependencias de Gradle en Cómo ver y depurar dependencias.
Puedes especificar las versiones solicitadas directamente, en un catálogo de versiones o en una lista de materiales (BoM).
Resolución de especificación de la versión directa
Las versiones de las dependencias que especifiques se convierten en candidatas para la resolución de versiones.
Por ejemplo, para solicitar la versión 1.7.3 de la biblioteca androidx.compose.ui:ui
como una dependencia en tu app/build.gradle.kts
, ejecuta el siguiente comando:
dependencies {
implementation("androidx.compose.ui:ui:1.7.3")
}
La versión 1.7.3 se convierte en una versión candidata. Gradle se resuelve en la versión más reciente entre la versión 1.7.3 y otras versiones de la misma biblioteca solicitadas por las dependencias transitivas.
Resolución del catálogo de versiones
Los catálogos de versiones definen variables para hacer un seguimiento de la versión de las dependencias que se usan en toda la aplicación. Si usas una variable del catálogo de versiones, las dependencias especificadas de esa variable se agregan a los candidatos para la resolución de versiones. Se ignoran las variables que no se usan en el catálogo de versiones.
Por ejemplo, para especificar la versión 1.7.3 de androidx.compose.ui:ui
como una dependencia en tu archivo gradle/libs.versions.toml
, ejecuta el siguiente comando:
[versions]
ui = "1.7.3"
[libraries]
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" }
Esto define una variable llamada libs.androidx.compose.ui
para representar la biblioteca. Esta versión no se considera candidata, a menos que uses esa variable para especificar una dependencia.
Para solicitar la biblioteca y su versión en tu app/build.gradle.kts
, haz lo siguiente:
dependencies {
implementation(libs.androidx.compose.ui)
}
Gradle resuelve del mismo modo que lo hizo para una especificación directa.
Resolución de la lista de materiales (BoM)
Las versiones de todas las bibliotecas que aparecen en la BoM se convierten en candidatas para la resolución de versiones. Ten en cuenta que las bibliotecas se usan como dependencias solo si se especifican como directas o indirectas. Se ignoran las demás bibliotecas de la BoM.
Las versiones de BoM afectan tus dependencias directas, así como todas las dependencias transitivas que aparecen en la BoM.
Por ejemplo, especifica una BoM como una dependencia de platform en tu app/build.gradle.kts
:
dependencies {
implementation(platform("androidx.compose:compose-bom:2024.10.00"))
implementation("androidx.compose.ui:ui")
}
Las bibliotecas que quieras usar como dependencias no requieren una especificación de versión. La versión solicitada proviene de la BoM.
Ten en cuenta que también puedes usar un catálogo de versiones a fin de crear variables para la BoM y las bibliotecas. Omite los números de versión en el catálogo de versiones para las bibliotecas que aparecen en una dependencia de BoM.
Por ejemplo, tu catálogo de versiones contiene la BoM y su número de versión, pero no especifica una versión para las bibliotecas a las que haces referencia desde la BoM:
[versions]
composeBom = "2024.10.00"
[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
Tu app/build.gradle.kts
hace referencia a la BoM y a las bibliotecas con las variables definidas en el catálogo de versiones:
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
}
La versión de esa biblioteca especificada en la BoM se convierte en una candidata para la resolución de Gradle. Además, todas las demás versiones de la biblioteca especificadas en la BoM se convierten en versiones candidatas, sin importar si las usas directamente como dependencias.
Por ejemplo, supongamos que una BoM especifica versiones para las bibliotecas A, B y C. Tu aplicación quiere usar directamente la biblioteca A como dependencia, así como la biblioteca D. La biblioteca D usa la biblioteca B como dependencia. Nada usa la biblioteca C.
Las bibliotecas A, B y D son dependencias de la aplicación; se ignora la biblioteca C. Gradle usa las versiones de A y B especificadas en la BoM como candidatas, aunque no especifiques directamente la biblioteca B como dependencia.
Si la biblioteca D solicita una versión de la biblioteca B anterior a 2.0.1, Gradle resuelve a 2.0.1. Si la biblioteca D solicita una versión posterior de la biblioteca B, Gradle resuelve a esa versión.