Android Gradle 隐形依赖的奇怪案例

翻译 2018年04月16日 10:54:57

相信 Android 开发者都有在 Android Studio 中升级 compileSdkVersion 的经历,这个时候如果你使用了 support 包,并同时升级,那么可能会出现一个错误提示。本文教你如何解决这个问题。

在 Android Studio 中,Gradle 构建过程大多数都是抽象的。作为一个新手 Android 开发者,我们在使用 Gradle 的时候首先遇到的问题通常都是如何在 build.gradle 中添加远程依赖。

让我们来看一个情形并学习如何查看依赖树,以及解决依赖相关的问题。

我正在开发一个项目,并且我想把构建版本提升到最新的 API 27。同时,我把 build.gradle 中的 appcompat-v7 扩展库也升级到了 27.0.2.然后我 sync 项目,出现了如下错误:

这里写图片描述

所有的 com.android.support 库都必须使用相同的版本

这个错误说我必须使用完全相同版本的扩展包。很直接,但是我的 build.gradle 中只有这一个扩展包。Android Studio 在说什么呢? ��上面提到的 com.android.support:animated-vector-drawable:27.0.2 和 com.android.support-v4:21.0.3 到底在哪?

这里写图片描述

如果只有 build.gradle 中的依赖那么事情会变得很简单,但事实并非如此。这些依赖可能有一些别的依赖,别的依赖中又有另一些依赖等等等等。这就叫传递依赖,Gradle 需要把所有的这些直接/间接的依赖打包到 app 当中。Android Studio 的错误提示就是在说这些传递依赖。

Gradle 一定有某种方式来解决所有的依赖。哪个库要添加?如果两个不同的库都依赖于相同的库的不同版本呢?我们来深入了解一下发生了什么。

要查看依赖树(Gradle 解决依赖的方式),我们可以打开 Android Studio 的终端,然后输入以下命令(Windows):

gradlew app:dependencies

mac:

./gradlew app:dependencies

这会展示所有构建变体的依赖树。我们可以在上面的命令中添加一个标识来查看特定变体的配置。比如: –configuration releaseCompileClasspath 将会展示 release 变体的依赖树。

上面命令的输出是这样的:

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 (*)

在查看问题之前理解依赖树的格式是非常重要的。先来看看下面的三个符号,它们只是用来格式化的:

  • — 是一个库分支的开始

| 表示继续显示这个库所依赖的分支

— 表示分支的结束

(*) 在一个库的后面表示这个库的更多依赖没有显示,因为它们已经在其他子树中列出来了。

最重要的符号是 ->

在 Gradle 中如果多个库依赖于相同的库的不同版本,那么它会做出选择。包含库的不同版本是不合理的。因此,Gradle 默认选择那个库的最新版本。

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

上面显示的是尽管 support-v4:21.0.3 依赖于 support-annotations:21.0.3 ,但是有一个新版本 support-annotations:27.0.2 在依赖树中,所以 27.0.2 将会被使用。

这里写图片描述

现在我们知道如何查看 Gradle 依赖树了,回到刚才的问题:所有的 com.android.support 库都必须使用完全相同的版本。

所有的扩展包都在 com.android.support 组中,我们在上面的依赖树中可以看到 com.android.support:support-v4:21.0.3 只是 21.0.3 版本的,没有使用最新的 27.0.2 版本。这里导致了冲突。

怎么解决这个问题呢?有几种方式:

  • 实现一个解决策略,让 Gradle 强制使用某个版本:
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'
    }
}
  • 在 build.gradle 中显式添加 com.android.support:support-v4:27.0.2 ,这样 Gradle 就会覆盖之前的旧版本。
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'
}

对于我来说,显式添加依赖看起来更加自然。在 build.gradle 中的注释会提醒我们再次更新时是否需要显式地添加这个依赖。

添加依赖后,再次 sync,错误提示就会消失了,现在我们再次运行命令会看到 support-v4:21.0.3 被标记为 -> 27.0.2 了。

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

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

Android 使用 Gradle 统一配置依赖管理

在介绍使用 Gradle 统一配置依赖管理前我们先来简单介绍一下 Gradle, Gradle 是一个基于 JVM 的构建工具,也是一款非常灵活强大的构建工具,支持  jcenter、maven、Iv...
  • QDJdeveloper
  • QDJdeveloper
  • 2017-03-31 14:32:16
  • 2987

android实现gradle动态依赖打包

一、gradle基本知识gradle是基于Groovy语言的,一个Android Project项目基本会生成三种gradle文件:module gradle、project gradle 和 set...
  • sinat_33878878
  • sinat_33878878
  • 2017-10-16 23:10:26
  • 332

android使用Gradle统一配置依赖版本

模块化 Android 多Moudle 统一配置
  • asddavid
  • asddavid
  • 2016-11-24 17:18:15
  • 3200

android studio 插件 gradle view 查看gradle依赖树

依赖分析在使用maven时,设置依赖时总也是会有一些冲突的意外。而eclipse 或 myeclipse 对maven的支持中,有个可以分析依赖树的工具,挺好用的。 那么android studio...
  • soslinken
  • soslinken
  • 2016-04-08 09:50:12
  • 10429

问题集锦——(一)Android Studio的Gradle添加重复依赖的问题

报错:Multiple dex files define Lcom/nineoldandroids/animation/Animator$AnimatorListener;在Android Studi...
  • Tomasyb
  • Tomasyb
  • 2017-07-19 10:08:51
  • 714

Android Studio(Gradle)解决库依赖冲突问题

最近在调整代码的时候,出现如下问题: 12345678910111213Cause: com.android.dex.DexException: Multiple dex files def...
  • u010944680
  • u010944680
  • 2016-08-15 16:57:14
  • 6548

android 中gradle依赖冲突解决

android项目开发中经常会遇到库依赖异常,大多是版本依赖的冲突问题,说明下常见的版本依赖冲突解决方式首页看下我们项目的依赖关系./gradlew dependencies :app:depende...
  • u012400222
  • u012400222
  • 2017-11-29 14:51:21
  • 295

如何使用github自制Android library开源依赖。可以生成gradle、maven、sbt、leigingen等版本

Android开发朋友们的福利呀!! 我们在Android开发过程中,少不了使用别人的第三方库,如:compile 'com.lovedise:permissiongen:0.0.6'。这个放在我...
  • zzq272804553
  • zzq272804553
  • 2016-12-30 10:33:48
  • 1149

Android Studio的Gradle添加重复依赖的问题

Android Studio运行项目时报错:Multiple dex files define Lcom/nineoldandroids/animation/Animator$AnimatorList...
  • yisizhu520
  • yisizhu520
  • 2015-11-20 22:33:20
  • 14863

Gradle 与 Android的相互依赖

Android应用的构建过程是一个复杂的过程,涉及到很多工具。首先所有的资源文件都会被编译,并且在一个R文件中引用,然后Java代码被编译,通过dex工具转换成dalvik字节码。最后这些文件都会被打...
  • halaoda
  • halaoda
  • 2017-11-24 11:02:26
  • 521
收藏助手
不良信息举报
您举报文章:Android Gradle 隐形依赖的奇怪案例
举报原因:
原因补充:

(最多只允许输入30个字)