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