Os arquivos de compilação especificam as dependências diretas, mas cada uma delas pode exigir outras. Essas dependências transitivas aumentam rapidamente o gráfico de dependências geral, geralmente com versões conflitantes.
Quando as partes minor
(novos recursos) ou patch
(correções de bugs) mudam, a biblioteca
ainda é compatível e tem menos probabilidade de afetar seu aplicativo.
Por exemplo, suponha que seu aplicativo dependa das bibliotecas A e B, que, por sua vez, dependem de diferentes versões da biblioteca C.
Nesse caso, o Gradle escolhe a versão mais recente da biblioteca C por padrão, o que pode causar problemas de compilação ou execução. Neste exemplo, a biblioteca C é resolvida para 2.1.1, mas observe que a biblioteca A solicitou a biblioteca C 1.0.3. A maior parte do número da versão mudou, indicando mudanças incompatíveis, como a remoção de funções ou tipos. Isso pode fazer com que as chamadas feitas da biblioteca A falhem.
O app pode ter dependências diretas que também são transitivas.
Em um caso como esse, dependências transitivas mais recentes podem substituir a versão que você solicita diretamente no app.
O Gradle analisa todas as versões candidatas de todas as dependências no gráfico para determinar a versão mais recente de cada dependência. É possível usar tarefas básicas do Gradle e ferramentas mais avançadas para determinar quais versões de cada dependência o Gradle resolveu. Comparar as mudanças nessa resolução é fundamental para entender e reduzir os riscos do upgrade.
Por exemplo, você pode usar a tarefa dependencies
do Gradle executando ./gradlew
app:dependencies
para exibir uma árvore de todas as dependências usadas pelo módulo do
app. Ao executar isso em um aplicativo que usa as bibliotecas, como mostrado na
Figura 2, vemos que
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 (*)
Essa parte do relatório mostra algumas das dependências resolvidas para a
configuração releaseRuntimeClasspath
.
Sempre que você encontrar ->
no relatório de dependências, um solicitante (seu aplicativo
ou outra biblioteca) vai usar uma versão dessa dependência que não é
esperada. Em muitos casos, isso não causa problemas, já que a maioria das bibliotecas é
criada para compatibilidade com versões anteriores. No entanto, algumas bibliotecas podem fazer
mudanças incompatíveis, e esse relatório pode ajudar a determinar de onde vêm os novos problemas
com o comportamento do aplicativo.
Mais detalhes sobre o uso dos relatórios de dependência do Gradle podem ser encontrados em Conferir e depurar dependências.
É possível especificar as versões solicitadas diretamente em um catálogo de versões ou em uma lista de materiais (BoM).
Resolução de especificação da versão direta
As versões das dependências especificadas se tornam candidatas à resolução de versão.
Por exemplo, para solicitar a versão 1.7.3 da biblioteca androidx.compose.ui:ui
como
uma dependência em app/build.gradle.kts
:
dependencies {
implementation("androidx.compose.ui:ui:1.7.3")
}
A versão 1.7.3 se torna uma versão candidata. O Gradle resolve a versão mais recente entre 1.7.3 e outras versões da mesma biblioteca solicitadas por dependências transitivas.
Resolução do catálogo de versões
Os catálogos de versões definem variáveis para rastrear a versão das dependências usadas em todo o aplicativo. Se você usar uma variável do catálogo de versões, as dependências especificadas dessa variável serão adicionadas aos candidatos à resolução de versão. As variáveis não utilizadas no catálogo de versões são ignoradas.
Por exemplo, para especificar a versão 1.7.3 do androidx.compose.ui:ui
como uma
dependência no arquivo gradle/libs.versions.toml
:
[versions]
ui = "1.7.3"
[libraries]
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" }
Isso define uma variável chamada libs.androidx.compose.ui
para representar a
biblioteca. Essa versão não é considerada uma candidata, a menos que você use essa
variável para especificar uma dependência.
Para solicitar a biblioteca e a versão dela no app/build.gradle.kts
:
dependencies {
implementation(libs.androidx.compose.ui)
}
O Gradle resolve da mesma forma que uma especificação direta.
Resolução da Lista de materiais (BOM, na sigla em inglês)
As versões de todas as bibliotecas que aparecem na BoM se tornam candidatas à resolução de versão. As bibliotecas só são usadas como dependências se especificadas como diretas ou indiretas. Outras bibliotecas no BOM são ignoradas.
As versões da BoM afetam suas dependências diretas, bem como todas as dependências transitivas que aparecem na BoM.
Por exemplo, especifique um BOM como uma dependência de plataforma no
app/build.gradle.kts
:
dependencies {
implementation(platform("androidx.compose:compose-bom:2024.10.00"))
implementation("androidx.compose.ui:ui")
}
As bibliotecas que você quer usar como dependências não exigem uma especificação de versão. A versão solicitada vem da BoM.
Você também pode usar um catálogo de versões para criar variáveis para a BoM e bibliotecas. Omita os números de versão no catálogo de versões para bibliotecas que aparecem em uma dependência da BOM.
Por exemplo, o catálogo de versões contém a BoM e o número de versão, mas não especifica uma versão para as bibliotecas referenciadas na 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" }
O app/build.gradle.kts
referencia a BoM e as bibliotecas usando as variáveis
definidas no catálogo de versões:
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
}
A versão da biblioteca especificada no BOM se torna um candidato para a resolução do Gradle. Além disso, todas as outras versões de biblioteca especificadas na BoM se tornam versões candidatas, mesmo que você não as use diretamente como dependências.
Por exemplo, suponha que um BOM especifique versões para as bibliotecas A, B e C. Seu aplicativo quer usar diretamente a biblioteca A como dependência, bem como a biblioteca D. A biblioteca D usa a biblioteca B como dependência. Nada usa a biblioteca C.
As bibliotecas A, B e D são dependências do aplicativo; a biblioteca C é ignorada. O Gradle usa as versões de A e B especificadas na BoM como candidatas, mesmo que você não especifique diretamente a biblioteca B como uma dependência.
Se a biblioteca D solicitou uma versão da biblioteca B anterior à 2.0.1, o Gradle é resolvido para a 2.0.1. Se a biblioteca D solicitar uma versão mais recente da biblioteca B, o Gradle vai resolver para essa versão.