Interdependências de ferramentas e bibliotecas

As dependências de build são componentes externos necessários para criar seu projeto. Um build pode depender de bibliotecas, plug-ins, subprojetos, do SDK do Android, ferramentas como os compiladores do Kotlin e do Java, ambientes de desenvolvimento como o Android Studio e o próprio Gradle.

Cada dependência pode exigir outras dependências. Chamamos essas dependências transitivas e podemos aumentar rapidamente as dependências gerais usadas pelo aplicativo. Quando você quer fazer upgrade de uma dependência, seja uma biblioteca, ferramenta ou o SDK do Android, esse upgrade pode ser em cascata, atualizando muitas outras dependências.

Muitas vezes, isso não causa problemas, já que muitas bibliotecas seguem um esquema conhecido como controle de versões semântico. Essas bibliotecas restringem os tipos de mudanças que fazem para oferecer compatibilidade com as versões anteriores.

O controle de versões semântico segue um formato major.minor.patch. Por exemplo, no número de versão 4.8.3, 4 é a versão major, 8 é a versão minor e 3 é o número patch. Quando a parte major muda, a biblioteca pode ter mudanças de ruptura na API ou no comportamento. Isso pode afetar o comportamento do build ou do aplicativo.

Quando as partes minor (novos recursos) ou patch (correções de bugs) mudam, os desenvolvedores da biblioteca informam que ela ainda é compatível e não vai afetar seu aplicativo.

É importante observar essas mudanças, porque várias ferramentas de upgrade de dependência podem ajudar.

Relacionamentos no build

Os builds do Android contêm relações entre:

  • Código-fonte: o código e os recursos que você controla
  • Dependências de biblioteca: bibliotecas ou módulos externos que seu projeto e subprojetos incluem ao criar
  • Ferramentas: compiladores, plug-ins e SDKs que traduzem a origem em um aplicativo ou biblioteca
Criar dependências e as relações delas
Figura 1. Criar relacionamentos

Código-fonte

O código-fonte é o código em Kotlin ou Java que você escreve no aplicativo ou na biblioteca. Para mais detalhes sobre o uso de C++, consulte Android NDK.

O código-fonte depende de bibliotecas (incluindo bibliotecas de execução Kotlin e Java) e do SDK do Android, além de exigir o compilador Kotlin ou Java correspondente.

Alguns códigos-fonte incluem anotações que exigem processamento adicional. Por exemplo, se você estiver escrevendo código do Jetpack Compose, adicione anotações como @Composable que precisam ser processadas pelo plug-in do compilador Kotlin do Compose. Outras anotações podem ser processadas por um processador de símbolos do Kotlin (KSP) ou por ferramentas de processamento de anotações separadas.

Dependências de biblioteca

As bibliotecas contêm bytecodes puxados como parte do seu aplicativo. Ele pode ser um Java JAR, uma biblioteca Android (AAR) ou um subprojeto no seu build. Muitas bibliotecas seguem o controle de versões semânticas, que pode ajudar a entender quando elas permanecem compatíveis (ou não) quando atualizadas.

As bibliotecas podem depender de outras bibliotecas para reutilização, o que é chamado de dependência transitiva. Isso reduz as dependências que você precisa gerenciar explicitamente. Especifique as dependências que você usa diretamente e o Gradle as puxa junto com essas dependências transitivas. Esteja ciente de que, à medida que você atualiza suas dependências diretas, elas podem atualizar essas dependências transitivas.

Às vezes, uma biblioteca pode exigir versões mínimas do SDK do Android no ambiente de execução (minSdk) ou no momento da compilação (compileSdk). Isso é necessário quando uma biblioteca usa funções incluídas no SDK do Android ou nas APIs do JDK fornecidas. O minSdk efetivo do aplicativo é o minSdk mais alto solicitado pelo aplicativo e todas as dependências de biblioteca diretas e transitivas dele.

O uso de algumas bibliotecas pode exigir o uso de um plug-in específico do Gradle. Esses plug-ins auxiliares geralmente instalam processadores de símbolos Kotlin ou outros processadores de anotações que geram código ou modificam a compilação da fonte para oferecer suporte ao uso de recursos da biblioteca. Por exemplo, o Jetpack Room inclui anotações e um KSP que os transforma em código gerado para recuperar e modificar dados em um banco de dados. O Jetpack Compose exige que o plug-in do compilador do Compose modifique funções anotadas para gerenciar como e quando essa função é executada novamente.

Ferramentas

Gradle

O Gradle é a ferramenta de build que lê os arquivos de build e gera o aplicativo ou biblioteca, além de expor uma API para plug-ins a fim de ampliar os recursos. O Gradle executa vários processos em uma ou mais máquinas virtuais Java, e os plug-ins Java chamam as ferramentas Java dentro do JDK.

Plug-ins do Gradle

Os plug-ins do Gradle estendem o Gradle definindo novas tarefas e configurações. Aplicar um plug-in ao build ativa recursos específicos, configurados como dados nos scripts. Para builds do Android, o Plug-in do Gradle mais importante é o Plug-in do Android para Gradle (AGP, na sigla em inglês).

Compiladores

O compilador Kotlin ou Java transforma o código-fonte em bytecode executável. O compilador Kotlin expõe uma API de plug-in que permite que a análise externa e a geração de código sejam executadas diretamente no compilador, acessando a estrutura de código analisada.

Plug-ins do compilador

Os plug-ins do compilador executam a análise e a geração de código dentro do compilador Kotlin enquanto ele analisa seu código. Eles são instalados quando você aplica os plug-ins do Gradle ao build.

SDK do Android

O SDK do Android contém a plataforma Android e as APIs Java para uma versão específica do Android, além das ferramentas correspondentes. Essas ferramentas ajudam a gerenciar o SDK, criar aplicativos e se comunicar e emular dispositivos Android.

Cada versão do SDK do Android oferece APIs Java específicas que o código-fonte pode acessar e suporte a dessugaramento para usar essas APIs em versões anteriores do Android.

JDK

O kit de desenvolvimento Java, que contém bibliotecas e executáveis do Java para compilar código-fonte Java e executar aplicativos Java. Há vários JDKs em um build do Android. Consulte Versões Java em builds do Android para mais detalhes.

Escopos do Gradle

O Gradle agrupa as dependências de biblioteca em diferentes escopos (chamados configurações na API do Gradle), permitindo que você especifique diferentes conjuntos de dependências de biblioteca para serem usados em diferentes partes do build. Por exemplo, provavelmente você não quer incluir bibliotecas de teste (como JUnit) no aplicativo ou biblioteca publicado, mas precisa delas ao criar e executar testes de unidade. Você também usa escopos para adicionar processadores de símbolos ou anotações para analisar seu código.

Por exemplo, o AGP define os escopos implementation e api, sua maneira de especificar se uma dependência precisa ser exposta aos usuários do subprojeto. Consulte Configurar dependências para descrições desses e de outros escopos usados em um build do Android.

Adicione dependências de biblioteca no bloco dependencies dos arquivos de build como strings 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'
}

ou em um catálogo de versões:

# 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" }

e especifique as variáveis geradas nos arquivos de build:

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
}