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.. 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 tentado 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 o 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. Sessão de Plugins e clicar em Browser repositories…. Na nova janela buscar por Gradle View e 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.
Contatos
Podem me encontrar pelo e-mail orafaaraujo@gmail.com, pelo skype orafaaraujo, e pelo slack/medium/twitter @orafaaraujo.
Feedbacks são bem-vindos!
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