The strange case of Android Gradle's invisible dependencies

I believe that Android developers have the experience of upgrading compileSdkVersion in Android Studio. At this time, if you use the support package and upgrade at the same time, an error message may appear. This article teaches you how to solve this problem.

In Android Studio, the Gradle build process is mostly abstract. As a novice Android developer, the first problem we encounter when using Gradle is usually how to add remote dependencies in build.gradle.

Let's look at a situation and learn how to view a dependency tree and solve dependency related problems.

I'm working on a project and I want to bump the build to the latest API 27. At the same time, I also upgraded the appcompat-v7 extension library in build.gradle to 27.0.2. Then I synced the project and the following error occurred:

write picture description here

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

This error says I have to use the exact same version of the extension pack. Straightforward, but I only have this one extension in my build.gradle. What is Android Studio saying? ��Where are the com.android.support:animated-vector-drawable:27.0.2 and com.android.support-v4:21.0.3 mentioned above?

write picture description here

Things would be easier if there were only dependencies in build.gradle, but it's not. These dependencies may have some other dependencies, some other dependencies within other dependencies, and so on. This is called transitive dependencies, and Gradle needs to package all these direct/indirect dependencies into the app. The error message from Android Studio is talking about these transitive dependencies.

Gradle must have some way to resolve all dependencies. Which library to add? What if two different libraries both depend on different versions of the same library? Let's take a deeper look at what's going on.

To view the dependency tree (the way Gradle resolves dependencies), we can open Android Studio's terminal and enter the following command (Windows):

gradlew app:dependencies

mac:

./gradlew app:dependencies

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

The output of the above command is this:

releaseCompileClasspath - Resolved configuration for compilation for variant: release
+--- com.android.databinding:library:1.3.1
|    +--- com.android.support:support-v4:21.0.3
|    |    \--- com.android.support:support-annotations:21.0.3 -> 27.0.2
|    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1
+--- com.android.databinding:baseLibrary:3.0.1
+--- com.android.databinding:adapters:1.3.1
|    +--- com.android.databinding:library:1.3 -> 1.3.1 (*)
|    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1
+--- com.android.support.constraint:constraint-layout:1.0.2
|    \--- com.android.support.constraint:constraint-layout-solver:1.0.2
\--- com.android.support:appcompat-v7:27.0.2
     +--- com.android.support:support-annotations:27.0.2
     +--- com.android.support:support-core-utils:27.0.2
     |    +--- com.android.support:support-annotations:27.0.2
     |    \--- com.android.support:support-compat:27.0.2
     |         +--- com.android.support:support-annotations:27.0.2
     |         \--- android.arch.lifecycle:runtime:1.0.3
     |              +--- android.arch.lifecycle:common:1.0.3
     |              \--- android.arch.core:common:1.0.0
     +--- com.android.support:support-fragment:27.0.2
     |    +--- com.android.support:support-compat:27.0.2 (*)
     |    +--- com.android.support:support-core-ui:27.0.2
     |    |    +--- com.android.support:support-annotations:27.0.2
     |    |    \--- com.android.support:support-compat:27.0.2 (*)
     |    +--- com.android.support:support-core-utils:27.0.2 (*)
     |    \--- com.android.support:support-annotations:27.0.2
     +--- com.android.support:support-vector-drawable:27.0.2
     |    +--- com.android.support:support-annotations:27.0.2
     |    \--- com.android.support:support-compat:27.0.2 (*)
     \--- com.android.support:animated-vector-drawable:27.0.2
          +--- com.android.support:support-vector-drawable:27.0.2 (*)
          \--- com.android.support:support-core-ui:27.0.2 (*)

It is very important to understand the format of the dependency tree before looking at the problem. Let's take a look at the following three symbols, they are only used for formatting:

  • — is the start of a library branch

| means to continue to display the branches that this library depends on

— indicates the end of a branch

(*) after a library means that more dependencies of this library are not shown because they are already listed in other subtrees.

The most important notation is ->

In Gradle it makes a choice if multiple libraries depend on different versions of the same library. It is not reasonable to include different versions of the library. Therefore, Gradle chooses the latest version of that library by default.

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

The above shows that although support-v4:21.0.3 depends on support-annotations:21.0.3, there is a new version support-annotations:27.0.2 in the dependency tree, so 27.0.2 will be used.

write picture description here

Now that we know how to view the Gradle dependency tree, back to the question: all com.android.support libraries must use the exact same version.

All extension packages are in the com.android.support group, we can see in the dependency tree above that com.android.support:support-v4:21.0.3 is only version 21.0.3, not using the latest 27.0. 2 version. Here's a conflict.

How to solve this problem? There are several ways:

  • Implement a resolution strategy to force Gradle to use a certain version:
android {
        configurations.all {
        // To resolve the conflict for com.android.databinding:library:1.3.1
        // dependency on support-v4:21.0.3        
        resolutionStrategy.force 'com.android.support:support-v4:27.0.2'
    }
}
  • Explicitly add com.android.support:support-v4:27.0.2 in build.gradle so that Gradle will overwrite the previous old version.
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    // To resolve the conflict for com.android.databinding:library:1.3.1
    // dependency on support-v4:21.0.3
    implementation 'com.android.support:support-v4:27.0.2'
    implementation 'com.android.support:appcompat-v7:27.0.2'
}

Explicitly adding dependencies seems more natural to me. A comment in build.gradle will remind us if we need to explicitly add this dependency when we update again.

After adding the dependencies, sync again, the error message will disappear, and now we run the command again and see that support-v4:21.0.3 is marked as -> 27.0.2.

https://pic3.zhimg.com/80/v2-...

原文链接:Android Gradle and the curious case of invisible dependency

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325526281&siteId=291194637