Adicionar dependências de compilação

O sistema de compilações Gradle no Android Studio facilita a inclusão de binários externos ou outros módulos de biblioteca na compilação como dependências. As dependências podem estar localizadas na sua máquina ou em um repositório remoto. Todas as dependências transitivas declaradas também serão automaticamente incluídas. Esta página descreve como usar dependências com um projeto do Android, incluindo detalhes sobre comportamentos e configurações específicos do Android Plugin for Gradle. Para obter orientações conceituais mais detalhadas sobre as dependências do Gradle, consulte também o guia do Gradle para gerenciamento de dependências. No entanto, lembre-se de que o projeto do Android deve usar apenas as configurações de dependência definidas nesta página.

Tipos de dependência

Para adicionar uma dependência a um projeto, especifique uma configuração de dependência como implementationno bloco dependencies do arquivo build.gradle.

Por exemplo, o arquivo build.gradle a seguir para um módulo do aplicativo inclui três tipos diferentes de dependências:

apply plugin: 'com.android.application'

android { ... }

dependencies {
    // Dependency on a local library module
    implementation project(":mylibrary")

    // Dependency on local binaries
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Dependency on a remote binary
    implementation 'com.example.android:app-magic:12.3'
}

Cada solicitação exige um tipo diferente de dependência de biblioteca:

Dependência de módulo de biblioteca local
implementation project(':mylibrary')

Esse código declara uma dependência de um módulo de biblioteca do Android chamado “mylibrary” (esse nome deve corresponder ao nome da biblioteca definido com um include: no arquivo settings.gradle). Ao criar seu aplicativo, o sistema compila o módulo de biblioteca e empacota o conteúdo compilado resultante no APK.

Dependência binária local
implementation fileTree(dir: 'libs', include: ['*.jar'])

O Gradle declara dependências nos arquivos JAR dentro do diretório module_name/libs/ do projeto porque ele lê caminhos relativos para o arquivo build.gradle.

Como alternativa, você pode especificar arquivos individuais da seguinte forma:

implementation files('libs/foo.jar', 'libs/bar.jar')
Dependência binária remota
implementation 'com.example.android:app-magic:12.3'

Na verdade, esse código é uma abreviação de:

implementation group: 'com.example.android', name: 'app-magic', version: '12.3'

Esse código declara uma dependência da versão 12.3 da biblioteca "app-magic", dentro do grupo de namespace "com.example.android".

Observação: dependências remotas como esta exigem que você declare os repositórios remotos adequados, onde o Gradle deve procurar a biblioteca. Se a biblioteca ainda não existir localmente, o Gradle a obterá no site remoto quando exigido pela compilação (como quando você clica em Sync Project with Gradle Files ou quando você executa uma compilação).

Configurações de dependência

Dentro do bloco dependencies, você pode declarar uma dependência de biblioteca usando uma entre várias configurações de dependência diferentes (como implementation acima). Cada configuração de dependência fornece ao Gradle instruções diferentes sobre como usar a dependência. A tabela a seguir descreve cada uma das configurações que podem ser usadas para uma dependência em um projeto do Android. A tabela também compara essas configurações às configurações obsoletas do Android Plugin para Gradle 3.0.0.

Nova configuração Configuração obsoleta Comportamento
implementation compile O Gradle adiciona a dependência ao caminho de classe de compilação e empacota a dependência no resultado de compilação. No entanto, quando o módulo configura uma dependência implementation, isso informa o Gradle de que você não quer que o módulo vaze a dependência para outros módulos no tempo da compilação. Ou seja, a dependência é disponibilizada a outros módulos apenas no tempo de execução.

O uso dessa configuração de dependência, em vez de api ou compile (obsoleto), pode resultar em melhorias consideráveis no tempo de compilação, já que isso reduz o número de módulos que o sistema de compilação precisa processar. Por exemplo, se uma dependência implementation alterar sua API, o Gradle recompilará apenas a dependências e os módulos que dependem diretamente dela. A maioria dos módulos de teste e aplicativos deve usar essa configuração.

api compile O Gradle adiciona a dependência ao caminho de classe de compilação e ao resultado de compilação. Quando um módulo inclui uma dependência api, informa ao Gradle que quer exportá-la de forma transitiva para outros módulos para que ela fique disponível a eles no tempo de execução e de compilação.

Essa configuração se comporta da mesma forma que compile (agora obsoleta). No entanto, use-a com cuidado e somente com dependências que você precisa exportar de modo transitivo para outros clientes ascendentes. Isso porque, se uma dependência api alterar a sua API externa, o Gradle recompilará todos os módulos que têm acesso a ela no tempo de compilação. Portanto, a existência de um grande número de dependências api pode aumentar consideravelmente o tempo de compilação. A menos que você queira expor a API de uma dependência para um módulo de teste separado, os módulos de aplicativos devem usar dependências implementation .

compileOnly provided O Gradle adiciona a dependência somente ao caminho de classe (ou seja, a dependência não é adicionada ao resultado da compilação). Isso é útil quando você está criando um módulo do Android e precisa da dependência durante a compilação, mas a presença durante o tempo de execução é opcional.

Se você usar essa configuração, o módulo de biblioteca deverá incluir uma condição de tempo de execução para verificar se a dependência está disponível e alterar seu comportamento de forma controlada para continuar funcionando, caso a dependência não esteja disponível. Isso ajuda a reduzir o tamanho do APK final, evitando a adição de dependências transientes não essenciais. Essa configuração se comporta da mesma forma que provided (obsoleta).

runtimeOnly apk O Gradle adiciona a dependência apenas ao resultado da compilação, para uso durante o tempo de execução. Ou seja, a dependência não é adicionada ao caminho de classe de compilação. Essa configuração se comporta da mesma forma que apk (obsoleta).
annotationProcessor compile Para adicionar uma dependência a uma biblioteca que seja um processador de anotações, é preciso adicioná-la ao caminho de classe do processador de anotações usando a configuração annotationProcessor. Usar essa configuração aprimora o desempenho de compilação, separando o caminho de classe da compilação do caminho de classe do processador de anotações. Se o Gradle encontrar processadores de anotações no caminho de classe da compilação, ele desativará a evasão de compilação, o que afeta negativamente o tempo de compilação. O Gradle 5.0 e versões posteriores ignoram os processadores de anotações encontrados no caminho de classe da compilação.

O Android Plugin para Gradle entenderá que uma dependência é um processador de anotações se o arquivo JAR contiver o seguinte arquivo:
META-INF/services/javax.annotation.processing.Processor. Se o plug-in detectar que há um processador de anotações no caminho de classe da compilação, ele gerará um erro de compilação.

As configurações acima são aplicadas ao conjunto de origem do projeto, que é aplicado a todas as variantes de compilação. Se, em vez disso, você quiser declarar uma dependência apenas para um conjunto de origem de uma variante de compilação específica ou para um conjunto de origem de teste, capitalize o nome da configuração de dependência e adicione um prefixo com o nome da variante de compilação ou do conjunto de origem de teste.

Por exemplo, para adicionar uma dependência implementation apenas à variação de produto "free” (usando uma dependência binária remota), o código é semelhante a:

dependencies {
    freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
}

No entanto, se quiser adicionar uma dependência para uma variante que combina uma variação de produto e um tipo de compilação, inicialize o nome da configuração no bloco configurations. O exemplo adiciona uma dependência runtimeOnly à variante de compilação "freeDebug" (usando uma dependência binária local):

configurations {
    // Initializes a placeholder for the freeDebugRuntimeOnly dependency
    // configuration.
    freeDebugRuntimeOnly {}
}

dependencies {
    freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
}

Para adicionar a dependência implementation para testes locais e instrumentados , o código é semelhante a:

dependencies {
    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

No entanto, algumas configurações não fazem sentido nessa situação. Por exemplo, como outros módulos não podem depender de androidTest, você receberá o seguinte aviso se usar a configuração androidTestApi:

WARNING: Configuration 'androidTestApi' is obsolete and has been replaced with
'androidTestImplementation'.

Adicionar processadores de anotações

Se você adicionar processadores de anotações ao caminho de classe da compilação, receberá uma mensagem de erro parecida com esta:

Error: Annotation processors must be explicitly declared now.

Para resolver esse erro, adicione processadores de anotações a seu projeto, configurando sua dependência com annotationProcessor, como mostrado abaixo:

dependencies {
    // Adds libraries defining annotations to only the compile classpath.
    compileOnly 'com.google.dagger:dagger:version-number'
    // Adds the annotation processor dependency to the annotation processor classpath.
    annotationProcessor 'com.google.dagger:dagger-compiler:version-number'
}

Observação: o Plug-in Android para Gradle 3.0.0 e versões posteriores não é mais compatível com o plug-in android-apt.

Passar argumentos para os processadores de anotações

Se você precisar passar os argumentos para um processador de anotações, use o bloco AnnotationProcessorOptions na configuração de compilação do seu módulo. Por exemplo, se você quiser passar tipos de dados primitivos como pares de chave-valor, é possível usar a propriedade argument, como mostrado abaixo:

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                argument "key1", "value1"
                argument "key2", "value2"
            }
        }
    }
}

No entanto, ao usar o Android Plugin para Gradle 3.2.0 e versões posteriores, você precisará passar argumentos de processador que representam arquivos ou diretórios usando a interface CommandLineArgumentProvider do Gradle.

Usar CommandLineArgumentProvider permite que você ou o autor do processador de anotações melhore a exatidão e o desempenho de compilações limpas graduais e em cache aplicando as anotações de tipo de propriedade de compilação gradual a cada argumento.

Por exemplo, a classe abaixo implementa CommandLineArgumentProvider e anota cada argumento do processador. A amostra também usa a sintaxe da linguagem Groovy e está incluída diretamente no arquivo build.gradle do módulo.

class MyArgsProvider implements CommandLineArgumentProvider {

    // Annotates each directory as either an input or output for the
    // annotation processor.
    @InputFiles
    // Using this annotation helps Gradle determine which part of the file path
    // should be considered during up-to-date checks.
    @PathSensitive(PathSensitivity.RELATIVE)
    FileCollection inputDir

    @OutputDirectory
    File outputDir

    // The class constructor sets the paths for the input and output directories.
    MyArgsProvider(FileCollection input, File output) {
        inputDir = input
        outputDir = output
    }

    // Specifies each directory as a command line argument for the processor.
    // The Android plugin uses this method to pass the arguments to the
    // annotation processor.
    @Override
    Iterable<String> asArguments() {
        // Use the form '-Akey[=value]' to pass your options to the Java compiler.
        ["-AinputDir=${inputDir.singleFile.absolutePath}",
         "-AoutputDir=${outputDir.absolutePath}"]
    }
}

android {...}

Após criar uma classe que implementa CommandLineArgumentProvider, você precisa inicializar e passá-la para o plug-in do Android usando a propriedade annotationProcessorOptions.compilerArgumentProvider , como mostrado abaixo.

// This is in your module's build.gradle file.
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                // Creates a new MyArgsProvider object, specifies the input and
                // output paths for the constructor, and passes the object
                // to the Android plugin.
                compilerArgumentProvider new MyArgsProvider(files("input/path"),
                                         new File("output/path"))
            }
        }
    }
}

Para saber mais sobre como implementar CommandLineArgumentProvider ajuda a melhorar o desempenho da compilação, leia Projetos Java em cache.

Desativar a verificação de erros do processador de anotações

Se você tiver dependências no caminho de classe da compilação que incluem processadores de anotações que não são necessários, será possível desativar a verificação de erros adicionando o seguinte ao arquivo build.gradle. Lembre-se de que os processadores de anotações adicionados ao caminho de classe da compilação ainda não serão incluídos ao caminho de classe do processador.

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath false
            }
        }
    }
}

Se você tiver problemas após migrar os processadores de anotações do seu projeto para o caminho de classe do processador, será possível permitir que os processadores de anotações no caminho de classe da compilação configurando includeCompileClasspath para true. No entanto, configurar essa propriedade para true não é recomendado, e a opção para isso será removida em uma atualização futura do plug-in do Android.

Excluir dependências transitivas

À medida que um aplicativo cresce no escopo, ele pode conter uma série de dependências, incluindo dependências diretas e transitivas (bibliotecas do seu aplicativo que dependem de bibliotecas importadas). Para excluir as dependências transitivas que você não precisa mais, é possível usar a palavra-chave exclude, conforme mostrado abaixo:

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

Excluir dependências transitivas das configurações de teste

Se você precisar excluir certas dependências transitivas dos seus testes, a amostra do código mostrada acima talvez não funcione conforme o esperado. Isso se deve porque uma configuração de teste (ex.: androidTestImplementation) estende a configuração implementation do módulo. Ou seja, sempre haverá dependências implementation quando o Gradle resolver a configuração.

Assim, para excluir dependências transitivas dos seus testes, é preciso fazer isso no tempo de execução, conforme mostrado abaixo:

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

Observação: ainda é possível usar a palavra-chave exclude no bloco de dependências, conforme mostrado no exemplo de código original na seção Excluir dependências para omitir dependências transitivas que são específicas à configuração de teste e não estão incluídas em outras configurações.

Usar gerenciamento de dependências com reconhecimento de variantes

O Android Plugin 3.0.0 ou posterior inclui um novo mecanismo de dependência que faz a correspondência automática de variantes ao consumir uma biblioteca. Isso significa que a variante debug de um aplicativo consome automaticamente a variante debug de uma biblioteca e assim por diante. Isso também funciona ao usar variações: a variante freeDebug de um aplicativo consumirá a variante freeDebug de uma biblioteca.

Para que o plug-in estabeleça correspondências precisas entre as variantes, será necessário fornecer fallbacks de correspondência para os casos em que uma correspondência direta é impossível. Verifique se seu aplicativo configura um tipo de compilação chamado "staging", mas uma das dependências de biblioteca dele não. Quando o plug-in tentar compilar a versão "staging" do aplicativo, ele não saberá qual versão da biblioteca usar, e você verá uma mensagem de erro semelhante à seguinte:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

Resolver erros de compilação relacionados à correspondência de variantes

O plug-in inclui elementos DSL para ajudar a controlar como o Gradle deve solucionar situações nas quais uma correspondência direta de variante entre um aplicativo e uma dependência não é possível. Consulte a tabela para determinar qual propriedade de DSL você deve usar para solucionar certos erros de compilação relacionados à correspondência de dependências com reconhecimento de variantes.

Causa do erro de compilaçãoSolução

Seu aplicativo inclui um tipo de compilação que uma dependência de biblioteca não tem.

Por exemplo, seu aplicativo inclui um tipo de compilação "staging", mas uma dependência inclui somente tipos de compilação "debug" e "release".

Observe que não há problema quando uma dependência de biblioteca inclui um tipo de compilação que seu aplicativo não tem. Isso ocorre porque o plug-in simplesmente nunca solicita esse tipo de compilação da dependência.

Use matchingFallbacks para especificar correspondências alternativas para um determinado tipo de compilação, conforme mostrado abaixo:

// In the app's build.gradle file.
android {
    buildTypes {
        debug {}
        release {}
        staging {
            // Specifies a sorted list of fallback build types that the
            // plugin should try to use when a dependency does not include a
            // "staging" build type. You may specify as many fallbacks as you
            // like, and the plugin selects the first build type that's
            // available in the dependency.
            matchingFallbacks = ['debug', 'qa', 'release']
        }
    }
}

Para uma determinada dimensão de variação que existe no aplicativo e na sua dependência de biblioteca, seu aplicativo inclui variações que a biblioteca não tem.

Por exemplo, tanto o aplicativo quanto suas dependências de biblioteca incluem uma dimensão de variação "tier". Entretanto, a dimensão "tier" no aplicativo inclui variações "free" e "paid", mas uma dependência inclui somente variações "demo" e "paid" para a mesma dimensão.

Observe que, para uma determinada dimensão de variação que existe no aplicativo e nas dependências de biblioteca, não há problema quando uma biblioteca inclui uma variação de produto que o aplicativo não tem. Isso ocorre porque o plug-in simplesmente nunca solicita essa variação da dependência.

Use matchingFallbacks para especificar correspondências alternativas para a variação de produto "free" do aplicativo, conforme mostrado abaixo:

// In the app's build.gradle file.
android {
    defaultConfig{
    // Do not configure matchingFallbacks in the defaultConfig block.
    // Instead, you must specify fallbacks for a given product flavor in the
    // productFlavors block, as shown below.
  }
    flavorDimensions 'tier'
    productFlavors {
        paid {
            dimension 'tier'
            // Because the dependency already includes a "paid" flavor in its
            // "tier" dimension, you don't need to provide a list of fallbacks
            // for the "paid" flavor.
        }
        free {
            dimension 'tier'
            // Specifies a sorted list of fallback flavors that the plugin
            // should try to use when a dependency's matching dimension does
            // not include a "free" flavor. You may specify as many
            // fallbacks as you like, and the plugin selects the first flavor
            // that's available in the dependency's "tier" dimension.
            matchingFallbacks = ['demo', 'trial']
        }
    }
}

Uma dependência de biblioteca inclui uma dimensão de variação que o aplicativo não tem.

Por exemplo, uma dependência de biblioteca inclui variações para uma dimensão "minApi", mas seu aplicativo inclui variações para apenas a dimensão "tier". Portanto, quando você quiser compilar a versão "freeDebug" do seu aplicativo, o plug-in não saberá se deve usar a versão "minApi23Debug" ou "minApi18Debug" da dependência.

Observe que não há problema quando seu aplicativo inclui uma dimensão de variação que uma dependência de biblioteca não tem. Isso ocorre porque o plug-in corresponde variações de apenas as dimensões que existem na dependência. Por exemplo, se uma dependência não incluir uma dimensão para ABIs, a versão "freeX86Debug" do aplicativo simplesmente usaria a versão "freeDebug" da dependência.

Use missingDimensionStrategy no bloco defaultConfig para especificar a variação padrão que o plug-in deve selecionar de cada dimensão ausente, conforme mostrado no exemplo abaixo. Você também pode modificar suas seleções no bloco productFlavors, de forma que cada variação possa especificar uma estratégia de correspondência diferente para uma dimensão ausente.

// In the app's build.gradle file.
android {
    defaultConfig{
    // Specifies a sorted list of flavors that the plugin should try to use from
    // a given dimension. The following tells the plugin that, when encountering
    // a dependency that includes a "minApi" dimension, it should select the
    // "minApi18" flavor. You can include additional flavor names to provide a
    // sorted list of fallbacks for the dimension.
    missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
    // You should specify a missingDimensionStrategy property for each
    // dimension that exists in a local dependency but not in your app.
    missingDimensionStrategy 'abi', 'x86', 'arm64'
    }
    flavorDimensions 'tier'
    productFlavors {
        free {
            dimension 'tier'
            // You can override the default selection at the product flavor
            // level by configuring another missingDimensionStrategy property
            // for the "minApi" dimension.
            missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
        }
        paid {}
    }
}

Configurar dependências do app Wear OS

Configurar dependências para um módulo de Wear OS é similar ao de qualquer outro módulo. Ou seja, eles usam as mesmas configurações de dependência, como implementation e compileOnly.

Os módulos de Wear também são compatíveis com gerenciamento de dependências com reconhecimento de variantes. Como resultado, se o módulo do aplicativo base tiver uma dependência em um módulo de Wear, cada variante do módulo de base consumirá a variante correspondente no módulo de Wear. Se você estiver compilando um app simples com uma dependência somente em um módulo de Wear, em que o módulo configura as mesmas variantes do seu módulo base, você precisará especificar a configuração wearApp no arquivo build.gradle do módulo base, conforme mostrado abaixo:

dependencies {
    // If the main and Wear app modules have the same variants,
    // variant-aware dependency management automatically matches
    // variants of the main app module with that of the wear module.
    wearApp project(':wearable')
}

Se você tiver vários módulos de Wear e quiser especificar um módulo diferente por variação de aplicativo, faça isso usando a configuração flavorWearApp , conforme indicado a seguir. No entanto, não é possível incluir outras dependências que usem a configuração wearApp:

dependencies {
    paidWearApp project(':wear1')
    demoWearApp project(':wear1')
    freeWearApp project(':wear2')
}

Repositórios remotos

Quando a dependência é relacionada a algo diferente de uma biblioteca ou árvore de arquivos local, o Gradle procura os arquivos nos repositórios on-line especificados no bloco repositories do arquivo build.gradle. A ordem usada para listar cada repositório determina a ordem de pesquisa de repositórios do Gradle para cada dependência de projeto. Por exemplo, se uma dependência estiver disponível em ambos os repositórios A e B, e você listar A primeiro, o Gradle fará o download da dependência do repositório A.

Por padrão, novos projetos do Android Studio especificam o Repositório Maven do Google e o JCenter como os locais de repositório no arquivo build.gradle de nível superior do projeto, conforme mostrado abaixo:

allprojects {
    repositories {
        google()
        jcenter()
    }
}

Se você quiser algo do repositório central Maven, adicione mavenCentral() ou, para um repositório local, use mavenLocal():

allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
        mavenLocal()
    }
}

Você também pode declarar repositórios Maven ou Ivy específicos da seguinte forma:

allprojects {
    repositories {
        maven {
            url "https://repo.example.com/maven2"
        }
        maven {
            url "file://local/repo/"
        }
        ivy {
            url "https://repo.example.com/ivy"
        }
    }
}

Para saber mais informações, consulte o guia de repositórios do Gradle.

Repositório Maven do Google

As versões mais recentes das seguintes bibliotecas do Android estão disponíveis no repositório Maven do Google:

Você pode ver todos os artefatos disponíveis no índice do repositório Maven do Google (veja abaixo informações sobre o acesso programático).

Para adicionar uma dessas bibliotecas à compilação, inclua o repositório Maven do Google no arquivo build.gradle de nível superior:

allprojects {
    repositories {
        google()

        // If you're using a version of Gradle lower than 4.1, you must instead use:
        // maven {
        //     url 'https://maven.google.com'
        // }
        // An alternative URL is 'https://dl.google.com/dl/android/maven2/'
    }
}

Em seguida, adicione a biblioteca desejada ao bloco dependencies do módulo. Por exemplo, a [biblioteca appcompat] ,(/topic/libraries/support-library/packages.html#v7-appcompat) é semelhante a:

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
}

No entanto, se você estiver tentando usar uma versão anterior das bibliotecas acima e a dependência falhar, significa que ela não disponível no repositório Maven. Em vez disso, obtenha a biblioteca no repositório off-line.

Acesso programático

Para acesso programático aos artefatos do Maven do Google, você pode obter uma lista XML dos grupos de artefatos de maven.google.com/master-index.xml. Em seguida, para qualquer grupo, você pode ver os nomes e versões de biblioteca em:

maven.google.com/group_path/group-index.xml

Por exemplo, as bibliotecas do grupo android.arch.lifecycle estão listadas em maven.google.com/android/arch/lifecycle/group-index.xml.

Também é possível fazer o download os arquivos POM e JAR em:

maven.google.com/group_path/library/version /library-version.ext

Por exemplo: maven.google.com/android/arch/lifecycle/compiler/1.0.0/compiler-1. 0.0.pom.

Repositório off-line do SDK Manager

Para as bibliotecas não disponíveis no repositório Maven do Google (normalmente, versões anteriores das bibliotecas), você deve fazer o download do pacote Google Repository off-line no SDK Manager.

Em seguida, você pode adicionar essas bibliotecas ao bloco dependencies da forma habitual.

As bibliotecas off-line são salvas em android_sdk/extras/.

Ordem de dependências

A ordem em que as dependências são listadas indica a prioridade de cada uma: a primeira biblioteca tem maior prioridade que a segunda, a segunda tem maior prioridade que a terceira e assim por diante. Essa ordem é importante quando recursos são combinados ou elementos do manifesto são combinados no aplicativo a partir das bibliotecas.

Por exemplo, se o projeto declarar:

  • A dependência de LIB_A e LIB_B (nessa ordem)
  • E LIB_A depende de LIB_C e LIB_D (nessa ordem)
  • E LIB_B também depende de LIB_C

A ordem de dependência combinada será a seguinte:

  1. LIB_A
  2. LIB_D
  3. LIB_B
  4. LIB_C

Isso garante que LIB_A e LIB_B possam substituir LIB_C. LIB_D mantém a prioridade maior que LIB_B porque LIB_A (que depende dele) tem prioridade maior que LIB_B.

Para obter mais informações sobre como manifestos de diferentes origens/dependências do projeto são combinados, consulte Combinar vários arquivos de manifesto.

Visualizar a árvore de dependências

Algumas dependências diretas podem ter suas próprias dependências. Essas próprias dependências são denominadas dependências transitivas. Em vez de exigir que você declare manualmente cada dependência transitiva, o Gradle coleta e adiciona automaticamente essas dependências para você. Para visualizar as dependências diretas e transitivas de um projeto, o Android Plugin for Gradle disponibiliza uma tarefa do Gradle que gera uma árvore de dependências para cada variante de compilação e conjunto de origem de teste.

Para executar a tarefa, faça o seguinte:

  1. Selecione View > Tool Windows > Gradle (ou clique em Gradle na barra de janelas de ferramentas).
  2. Expanda AppName > Tasks > android e clique duas vezes em androidDependencies. Depois que o Gradle executa a tarefa, a janela Run deve ser aberta para exibir a saída.

O exemplo de saída a seguir mostra a árvore de dependências da variante de compilação de depuração e inclui a dependência do módulo de biblioteca local e a dependência remota do exemplo anterior.

Executing tasks: [androidDependencies]
:app:androidDependencies
debug
/**
 * Both the library module dependency and remote binary dependency are listed
 * with their transitive dependencies.
 */
+--- MyApp:mylibrary:unspecified
|    \--- com.android.support:appcompat-v7:28.0.0
|         +--- com.android.support:animated-vector-drawable:28.0.0
|         |    \--- com.android.support:support-vector-drawable:28.0.0
|         |         \--- com.android.support:support-v4:28.0.0
|         |              \--- LOCAL: internal_impl-28.0.0.jar
|         +--- com.android.support:support-v4:28.0.0
|         |    \--- LOCAL: internal_impl-28.0.0.jar
|         \--- com.android.support:support-vector-drawable:28.0.0
|              \--- com.android.support:support-v4:28.0.0
|                   \--- LOCAL: internal_impl-28.0.0.jar
\--- com.android.support:appcompat-v7:28.0.0
     +--- com.android.support:animated-vector-drawable:28.0.0
     |    \--- com.android.support:support-vector-drawable:28.0.0
     |         \--- com.android.support:support-v4:28.0.0
     |              \--- LOCAL: internal_impl-28.0.0.jar
     +--- com.android.support:support-v4:28.0.0
     |    \--- LOCAL: internal_impl-28.0.0.jar
     \--- com.android.support:support-vector-drawable:28.0.0
          \--- com.android.support:support-v4:28.0.0
               \--- LOCAL: internal_impl-28.0.0.jar
...

Para saber mais sobre como gerenciar as dependências no Gradle, consulte Conceitos básicos sobre o gerenciamento de dependências no guia do usuário do Gradle.

Corrigir erros de resolução de dependência

Quando você adicionar várias dependências ao projeto do seu aplicativo, essas dependências diretas e transitivas podem entrar em conflito. O Android Plugin para Gradle tenta resolver esses conflitos, mas alguns deles podem levar a erros de tempo de execução ou compilação.

Para ajudar a investigar quais dependências contribuem com erros, examine a árvore de dependências do aplicativo e procure dependências que aparecem mais de uma vez ou versões conflitantes.

Se não for possível identificar facilmente a dependência duplicada, tente usar a IU do Android Studio para procurar dependências que incluem a classe duplicada da seguinte forma:

  1. Selecione Navigate > Class na barra de menus.
  2. Na caixa de diálogo pop-up de pesquisa, verifique se a caixa ao lado de Include non-project items está marcada.
  3. Digite o nome da classe que aparece no erro de compilação.
  4. Examine os resultados das dependências que incluem a classe.

As seguintes seções descrevem os tipos diferentes de erros de resolução de dependência que você talvez tenha e como corrigi-los.

Corrigir erros de classe duplicados

Se uma classe aparecer mais de uma vez no caminho de classe do tempo de execução, você receberá um erro parecido com este:

Program type already present com.example.MyClass

Normalmente, esse erro ocorre devido a uma das seguintes circunstâncias:

  • Uma dependência binária inclui uma biblioteca que o aplicativo também inclui como uma dependência direta. Por exemplo, o método declara uma dependência direta de Biblioteca A e Biblioteca B, mas a Biblioteca A já inclui a Biblioteca B em seu binário.
    • Para resolver esse problema, remova a Biblioteca B como dependência direta.
  • O aplicativo tem uma dependência binária local e uma dependência binária remota na mesma biblioteca.
    • Para resolver esse problema, remova uma das dependências binárias.

Corrigir conflitos entre caminhos de classe

Quando o Gradle resolve o caminho de classe da compilação, ele primeiro resolve o caminho de classe do tempo de execução e usa o resultado para determinar quais versões das dependências devem ser adicionadas ao caminho de classe de compilação. Em outras palavras, o caminho de classe do tempo de execução determina os números de versão necessários para dependências idênticas nos caminhos de classe descendentes.

O caminho de classe de tempo de execução do app também determina os números da versão que o Gradle exige para corresponder dependências no caminho de classe de tempo de execução para o APK de teste do aplicativo. A hierarquia dos caminhos de classe está descrita na imagem 1.

Imagem 1. Números da versão das dependências que aparecem em vários caminhos de classe precisam corresponder a esta hierarquia.

Se as versões conflitantes da mesma dependência apareceram em vários caminhos de classe, talvez você receba um erro parecido com este:

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

Você pode perceber esse conflito quando, por exemplo, seu aplicativo incluir uma versão de uma dependência usando a implementation configuração de dependência ,e um módulo de biblioteca incluir uma versão diferente da dependência usando a configuração runtimeOnly. Para resolver esse problema, faça uma das seguintes ações:

  • Inclua a versão desejada da dependência como uma dependência api a seu módulo de biblioteca. Ou seja, somente seu módulo de biblioteca declara a dependência, mas o módulo do aplicativo também terá acesso transitivo à API.
  • Como alternativa, é possível declarar a dependência em ambos os módulos, mas você deve se certificar de que cada módulo use a mesma versão da dependência. Considere configurar propriedades em todo o projeto para garantir que as versões de cada dependência permaneçam consistentes em todo o projeto.

Aplicar lógica de compilação personalizada

Esta seção descreve os tópicos avançados que são úteis para estender o Plugin Android para Android ou para escrever seu próprio plug-in.

Publicar dependências variantes na lógica personalizada

Uma biblioteca pode ter funcionalidades que outros projetos ou subprojetos talvez queiram usar. Publicar uma biblioteca é o processo de disponibilização da biblioteca aos clientes. As bibliotecas podem controlar quais dependências seus clientes terão acesso no tempo de compilação e execução.

Existem duas configurações separadas que possuem as dependências transitivas de cada caminho de classe. Elas podem ser usadas pelos clientes para consumir a biblioteca conforme descrito abaixo:

  • variant_nameApiElements: Essa configuração possui as dependências transitivas que estão disponíveis aos clientes no tempo de compilação.
  • variant_nameRuntimeElements: Essa configuração possui as dependências transitivas que estão disponíveis aos clientes no tempo de execução.

Para saber mais sobre as relações entre as diferentes configurações, acesse As configurações de plug-in da Biblioteca Java.

Estratégias de resolução de dependências personalizadas

Um projeto pode incluir uma dependência em duas versões diferentes da mesma biblioteca, o que pode resultar em conflitos de dependência. Por exemplo, se o projeto depender da versão 1 do módulo A e da versão 2 do módulo B, e o módulo A depende transitivamente da versão 3 do módulo B, ocorre um conflito de versão de dependência.

Para resolver esse conflito, o Plugin Android para Gradle usa a seguinte estratégia de resolução de dependência: quando o plug-in detectar que as diferentes versões do mesmo módulo estão no gráfico de dependência, por padrão, ele escolherá aquele com o número de versão mais alto.

No entanto, talvez essa estratégia não funcione sempre como o esperado. Para personalizar a estratégia de resolução de dependência, use as seguintes configurações para resolver dependências específicas de uma variante que são necessárias para sua tarefa:

  • variant_nameCompileClasspath: Essa configuração contém a estratégia de resolução do caminho de classe da compilação de uma dada variante.
  • variant_nameRuntimeClasspath: Essa configuração contém a estratégia de resolução do caminho de classe do tempo de execução de uma dada variante.

O Plugin Android para Gradle inclui coletores que podem ser usados para acessar os objetos de configuração de cada variante. Assim, é possível usar a API da variante para consultar a resolução da dependência, conforme mostrado no exemplo abaixo:

android {
    applicationVariants.all { variant ->
        // Return compile configuration objects of a variant.
        variant.getCompileConfiguration().resolutionStrategy {
        // Use Gradle's ResolutionStrategy API
        // to customize how this variant resolves dependencies.
            ...
        }
        // Return runtime configuration objects of a variant.
        variant.getRuntimeConfiguration().resolutionStrategy {
            ...
        }
        // Return annotation processor configuration of a variant.
        variant.getAnnotationProcessorConfiguration().resolutionStrategy {
            ...
        }
    }
}