Trabalhando com dependências duplicadas no Gradle
Dependendo do projeto, as dependências do Gradle podem ser um problema para o desenvolvedor. Isso acontece quando algumas bibliotecas que importamos no projeto usam outras bibliotecas dentro delas em versões diferentes. Veja como resolver.
Dependendo do projeto, as dependências do Gradle podem ser um problema para o desenvolvedor. Isso acontece quando algumas bibliotecas que importamos no projeto usam outras bibliotecas dentro delas em versões diferentes. Quando isso acontece, o Gradle exibe a mensagem de Conflict with dependency. Para resolver isso, temos algumas opções.
Exemplo
Para exemplificar, será usado um cenário onde o projeto compila a biblioteca de Suporte v7 e compila a biblioteca de testes Espresso.
dependencies {
compile 'com.android.support:appcompat-v7:25.1.0'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
}
Quando tentamos sincronizar o projeto, o Android Studio irá avisar da duplicidade da biblioteca de Suporte de Anotações, pois ambas bibliotecas importadas a utilizam, porém em versões diferentes (a Suporte V7 usa a versão 25.1.0 e a Espresso usa a versão 23.1.1).

Analisando duplicidades
Linha de comando
Execute o comando no arquivo gradlew localizado na raiz do projeto:
- ./gradlew app:dependencies (Linux e Mac OS X)
- gradlew app:dependencies (Windows, usando gradlew.bat)
(Onde app: é o modulo).
O comando irá exibir a lista de dependências de cada biblioteca usada no projeto. Abaixo está o que há por dentro da biblioteca do Espresso e da Suporte V7, respectivamente:
\--- com.android.support.test.espresso:espresso-core:2.2.2
+--- com.squareup:javawriter:2.1.1
+--- com.android.support.test:rules:0.5
| \--- com.android.support.test:runner:0.5
| +--- com.android.support:support-annotations:23.1.1
| +--- junit:junit:4.12
| | \--- org.hamcrest:hamcrest-core:1.3
| \--- com.android.support.test:exposed-instrumentation-api-publish:0.5
+--- com.android.support.test:runner:0.5 (*)
+--- javax.inject:javax.inject:1
+--- org.hamcrest:hamcrest-library:1.3
| \--- org.hamcrest:hamcrest-core:1.3
+--- com.android.support.test.espresso:espresso-idling-resource:2.2.2
+--- org.hamcrest:hamcrest-integration:1.3
| \--- org.hamcrest:hamcrest-library:1.3 (*)
+--- com.google.code.findbugs:jsr305:2.0.1
\--- javax.annotation:javax.annotation-api:1.2
\--- com.android.support:appcompat-v7:25.1.0
+--- com.android.support:support-annotations:25.1.0
+--- com.android.support:support-v4:25.1.0
| +--- com.android.support:support-compat:25.1.0
| | \--- com.android.support:support-annotations:25.1.0
| +--- com.android.support:support-media-compat:25.1.0
| | +--- com.android.support:support-annotations:25.1.0
| | \--- com.android.support:support-compat:25.1.0 (*)
| +--- com.android.support:support-core-utils:25.1.0
| | +--- com.android.support:support-annotations:25.1.0
| | \--- com.android.support:support-compat:25.1.0 (*)
| +--- com.android.support:support-core-ui:25.1.0
| | +--- com.android.support:support-annotations:25.1.0
| | \--- com.android.support:support-compat:25.1.0 (*)
| \--- com.android.support:support-fragment:25.1.0
| +--- com.android.support:support-compat:25.1.0 (*)
| +--- com.android.support:support-media-compat:25.1.0 (*)
| +--- com.android.support:support-core-ui:25.1.0 (*)
| \--- com.android.support:support-core-utils:25.1.0 (*)
+--- com.android.support:support-vector-drawable:25.1.0
| +--- com.android.support:support-annotations:25.1.0
| \--- com.android.support:support-compat:25.1.0 (*)
\--- com.android.support:animated-vector-drawable:25.1.0
\--- com.android.support:support-vector-drawable:25.1.0 (*)
Ambas bibliotecas estão utilizando a com.android.support:support porém com versões diferentes (destacado em negrito).
Plugin do relatório de projeto
Para algo mais “visual”, o Gradle oferece um plugin para gerar o mesmo relatório acima via página HTML, com opção de expandir e recolher as dependências internas para melhor navegação.
Para isso, é necessário configurar o plugin no build.gradle do seu modulo (geralmente, app/build.gradle).
apply plugin: 'com.android.application' apply plugin: 'project-report'
Depois de tentar sincronizar, será possível rodar o comando:
- ./gradlew htmlDependencyReportTask (Linux e Mac OS X)
- gradlew htmlDependencyReportTask (Windows, usando gradlew.bat)
Feito isso, você poderá abrir o relatório pelo seu Navegador. Ele está em:
{Seu Projeto}/app/build/reports/project/dependencies/index.html
Plugin Android Studio
Também existe um plugin para o Android Studio que permite ver a arvore de dependência dentro da IDE. Ele se chama Gradle View e para instalá-lo no Android Studio basta ir em File > Settings. Na sessão de Plugins, clique em Browser repositories…. Na nova janela, buscar por Gradle View e clicar em Install.

Reinicie o Android Studio e agora aparecerá esta aba na parte inferior direita:

Obrigado especial ao Ray Holder pela excelente biblioteca.
Resolvendo o problema
Ambas soluções propostas serão feitas no mesmo lugar em que se declara as dependências.
Exclude
Com a tag exclude, configuramos para o Gradle excluir a dependência interna desejada. Podemos identificá-la por grupo (tag exclude group), ou por nome (tag exclude module) ou por ambos.
dependencies {
compile 'com.android.support:appcompat-v7:25.1.0'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
exclude group: 'com.android.support'
exclude module: 'support-annotations'
exclude group: 'com.android.support', module: 'support-annotations'
}
Assim é configurado que a biblioteca não irá compilar a dependência citada no exclude e utilizará outra encontrada dentro do projeto como um todo.
Force
Outra opção seria forçar o projeto todo a usar uma versão especifica:
configurations.all {
resolutionStrategy {
force 'com.android.support:support-annotations:25.1.0'
}
}
Conclusão
A solução mais sensata é remover as dependências internas mais desatualizadas do projeto (usando exclude).
A desvantagem de forçar uma versão de uma biblioteca no projeto (usando force) é que se alguma biblioteca for atualizada e sua dependência interna também for atualizada, ela continuará a utilizar a versão fixada no force mesmo assim. Por exemplo, se biblioteca de Suporte v7 for atualizada e a biblioteca Suporte de Anotações utilizada internamente também for atualizada, ela continuará usando a versão fixada no force, podendo causar outros problemas, como ausência de funcionalidades que garantem o bom funcionamento da V7.
E, consequentemente, excluindo a dependência mais desatualizada, garantimos que a dependência será atualizada automaticamente caso a biblioteca atualize.
Considerações finais
Documentação oficial
Na documentação do Gradle há uma parte falando sobre listar as depedências, utilizar plugin de relatório, excluir dependências e resolução de conflitos.
Comunidade Android
Participe do maior forum sobre Android no Brasil no slack Android Dev BR:
- Site: http://www.androiddevbr.org
- Convite: http://slack.androiddevbr.org






