Android Gradle and the curious case of invisible dependency

Ashesh Bharadwaj
ProAndroidDev
Published in
4 min readJan 30, 2018

In Android Studio, the Gradle build process is largely abstracted. As a new Android Developer, our first encounter with Gradle is usually to add a remote dependency in the build.gradle file.

Let us look at a situation to learn how to read the dependency tree and resolve issues related to dependency.

I am working on a project and I want to upgrade the build to target latest API 27. Among other changes, I also update the version of appcompat-v7 support library dependency to 27.0.2 in build.gradle. After making the changes when I sync the project, following error is shown in build.gradle:

All com.android.support libraries must use the exact same version…

The error says that I must use the exact same version of support libraries. Fair enough, but I have this one support library only in my build.gradle. What’s Android Studio talking about? 😕 Where are these libraries com.android.support:animated-vector-drawable:27.0.2 or com.android.support-v4:21.0.3 mentioned in the error text?

I can’t see the dependencies but Android Studio says they are there 😱

Things would have been simple if only the dependencies in build.gradle had to be included in the app but that’s not the case. These dependencies could further have their own dependencies and those dependencies could have their own and so on. This is called Transitive dependency and Gradle needs to include all the direct/indirect dependencies in the app. What’s happening is that Android Studio error text is talking about these transitive dependencies.

There has to be a way how Gradle resolve all these dependencies. Which libraries to include? What if two different libraries have a dependency to the same library but different versions? Let’s take a dive to see what’s happening.

To view the dependency tree (the way Gradle resolve the dependencies), we can go to Android Studio Terminal tab located at the bottom and enter the following command(Windows):

gradlew app:dependencies

This will show dependency resolution tree for all build variants. We can add a flag to the above command to view configuration for specific build variant. For example --configuration releaseCompileClasspath will show us dependency tree for release variant.

Here is the output of the above command

Gradle dependency tree with version conflict

Before looking for the issue it’s important to understand the format of the dependency tree. Let’s talk about the following three symbols first which are for formatting purpose only:

+ --- is the start of a library branch
| continuation of the branch showing the libraries it depend on
\--- is the end of a library branch

A (*) at the end of a library means that further dependencies of this library are not shown as they are already listed in some other subtree.

Most important symbol is ->

If Gradle finds out multiple dependency to the same library but different versions then it has to make a choice. Including different versions of the same library wouldn’t make sense. In such case, Gradle by default chooses the newest version of that library.

| + — — com.android.support:support-v4:21.0.3
| | \ — — com.android.support:support-annotations:21.0.3 -> 27.0.2

Above, Gradle is telling that although the support-v4:21.0.3 depends on support-annotations:21.0.3 there is also a dependency to newer version support-annotations:27.0.2 in the dependency tree so 27.0.2 will be used.

com.android.support:support-annotations version 21.0.3 resolving to version 27.0.2

Now that we know how to read the Gradle dependency resolution tree, let’s get back to the issue: All com.android.support libraries must use the exact same version.

All support libraries belong to the following group com.android.support. As we see in Gradle dependency tree, com.android.support:support-v4:21.0.3 is the only support library with version 21.0.3 and not resolved to the newest version 27.0.2. This is causing the conflict.

How to resolve this issue? There are few ways to do it:

  • To implement a resolution strategy and forcing Gradle to use a particular version of the library.
  • To explicitly add com.android.support:support-v4:27.0.2 in build.gradle. This will let Gradle override older version with new one.

To me explicitly adding the dependency in build.gradle seems to be more natural. A comment in the build.gradle would help us remind when we again update the libraries to check if it’s still required to add it explicitly.

Once added and project synced, the error text will be gone. Now if we run the dependency command again we will see that support-v4:21.0.3 is resolving to -> 27.0.2

support-v4:21.0.3 is now resolved to -> 27.0.2

Most of the time Gradle would resolve the dependencies correctly. In case it doesn’t for the reason we found here or some other issue, we should be able to find out the cause and resolve it. I hope this article brings us one step closer to understand the Gradle dependency tree and resolution.

Thanks for reading this article. You can connect with me on LinkedIn

If you like the article, please recommend it by hitting the clap icon 👏 Let’s enable each other with the power of knowledge.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Ashesh Bharadwaj

Google Certified Android Developer, enjoying the journey to the future of personal data space. www.linkedin.com/in/asheshb

Responses (4)

What are your thoughts?