|
|
|
|
移动端
创建专栏

Gradle 的依赖关系处理不当,可能导致你编译异常!解决方案在此!

当我们作为一个初学者接触 Gradle 的时候,大部分时间在使用它来添加依赖库。而你所依赖的依赖库,可能又依赖其他的库,这非常的常见,这样的情况被称为依赖传递。

作者:张旸 译|2018-04-10 15:44

技术沙龙 | 邀您于8月25日与国美/AWS/转转三位专家共同探讨小程序电商实战

当我们作为一个初学者接触 Gradle 的时候,大部分时间在使用它来添加依赖库。而你所依赖的依赖库,可能又依赖其他的库,这非常的常见,这样的情况被称为依赖传递。

这样错综复杂的依赖关系,如果处理不好,可能达不到你预期的效果,而你有深究过吗?

我们带着问题来看看如何解决 Gradle 依赖关系导致的问题。

在 Android Studio 中,Gradle 构建过程对于开发者来说,很大程度上是抽象的。作为一个新的 Android 开发者,我们第一次遇到 Gradle 通常是在 build.gradle 文件中添加一个远程依赖项。

让我们看看如何阅读 Gradle 依赖关系树,并解决与依赖关系有关的问题。

这是我工作中管理的一个项目,我想将 targetVersion 升级到 27,我也在 Gradle 中,更新了新版的 appcompat-v7 支持库到最新的依赖版本 27.0.2。在更改之后,同步项目,在 build.gradle 中出现以下错误提示:

该错误表示我必须使用完全相同版本的支持库。可是我只在我的 build.gradle 中,使用了这个支持库。

Android Studio 的这个提示到底是什么意思?

这个错误提示中,提及到的 com.android.support:animated-vector-drawable:27.0.2或com.android.support-v4:21.0.3 是在哪里又被引用了?

如果只是应用程序的直接依赖库,只需要在 build.gradle 中指明依赖就好了,这样非常的清晰明了。但是实际情况并非如此,这些依赖关系可能会进一步拥有自己的依赖关系,这被称为 依赖传递 。Gradle 需要在应用中包含所有的直接或者间接的依赖。

前面 Android Studio 提示的错误信息,正是我们现在讨论的这些传递性依赖关系导致的。

Gradle 必须解决所有的这些依赖关系。包含使用了哪些库?如果两个不同的库对同一个库有不同版本的依赖关系,会发生什么问题?

要查看 Gradle 依赖关系树(Gradle 解析依赖关系的方式),我们可以到位于 Android Studio 底部的 Terminal 选项卡并输入以下命令:

  1. gradlew app:dependencies 

这将显示所有 构建变体 的依赖关系解析树。我们可以在上面的命令中添加一个标识来查看特定构建变体的配置。例如 --configuration releaseCompileClasspath将向我们展示 release 变体的依赖树。

关于构建变体,建议阅读官方文档:

https://developer.android.com/studio/build/build-variants.html

以上是上述命令的输出:

  1. releaseCompileClasspath - Resolved configuration for compilation for variant: release 
  2. +--- com.android.databinding:library:1.3.1 
  3. |    +--- com.android.support:support-v4:21.0.3 
  4. |    |    \--- com.android.support:support-annotations:21.0.3 -> 27.0.2 
  5. |    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1 
  6. +--- com.android.databinding:baseLibrary:3.0.1 
  7. +--- com.android.databinding:adapters:1.3.1 
  8. |    +--- com.android.databinding:library:1.3 -> 1.3.1 (*) 
  9. |    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1 
  10. +--- com.android.support.constraint:constraint-layout:1.0.2 
  11. |    \--- com.android.support.constraint:constraint-layout-solver:1.0.2 
  12. \--- com.android.support:appcompat-v7:27.0.2 
  13.      +--- com.android.support:support-annotations:27.0.2 
  14.      +--- com.android.support:support-core-utils:27.0.2 
  15.      |    +--- com.android.support:support-annotations:27.0.2 
  16.      |    \--- com.android.support:support-compat:27.0.2 
  17.      |         +--- com.android.support:support-annotations:27.0.2 
  18.      |         \--- android.arch.lifecycle:runtime:1.0.3 
  19.      |              +--- android.arch.lifecycle:common:1.0.3 
  20.      |              \--- android.arch.core:common:1.0.0 
  21.      +--- com.android.support:support-fragment:27.0.2 
  22.      |    +--- com.android.support:support-compat:27.0.2 (*) 
  23.      |    +--- com.android.support:support-core-ui:27.0.2 
  24.      |    |    +--- com.android.support:support-annotations:27.0.2 
  25.      |    |    \--- com.android.support:support-compat:27.0.2 (*) 
  26.      |    +--- com.android.support:support-core-utils:27.0.2 (*) 
  27.      |    \--- com.android.support:support-annotations:27.0.2 
  28.      +--- com.android.support:support-vector-drawable:27.0.2 
  29.      |    +--- com.android.support:support-annotations:27.0.2 
  30.      |    \--- com.android.support:support-compat:27.0.2 (*) 
  31.      \--- com.android.support:animated-vector-drawable:27.0.2 
  32.           +--- com.android.support:support-vector-drawable:27.0.2 (*) 
  33.           \--- com.android.support:support-core-ui:27.0.2 (*) 

在查找目的之前,理解 Gradle 依赖关系树的格式很重要。

先来谈谈以下三个符号,它们的目的仅用于格式化:

  • +- - - 是依赖分支库的开始。
  • |  标识还是在之前的依赖库中的依赖,显示它依赖的库。
  • \- - - 是依赖库的末尾。

星号(*) 在依赖库的末尾,意味着该库的进一步依赖关系不会显示,因为它们已经列在其他某个子依赖树中。

最重要的标识是 -> 。

如果 Gradle 发现多个依赖库都依赖到同一个库但是不同版本,那么它必须做出选择。毕竟包含同一个库的不同版本是没有意义的。在这种情况下,Gradle 默认选择该库的最新版本。

例如:

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

在上面,Gradle 告诉说,在 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。正如我们在 Gradle 的依赖关系树中看到的那样,com.android.support:support-v4:21.0.3 是唯一具有版本 21.0.3 并且未解析到最新版本的支持库 27.0.2,这就是造成冲突的原因。

如何解决这个问题?有几种方式,可以做到这一点:

1、通过 ResolutionStrategy

通过 ResolutionStrategy 强制指定 Gradle 的版本。

  1. android { 
  2.         configurations.all { 
  3.         // To resolve the conflict for com.android.databinding:library:1.3.1 
  4.         // dependency on support-v4:21.0.3         
  5.         resolutionStrategy.force 'com.android.support:support-v4:27.0.2' 
  6.     } 

关于 ResolutionStrategy 的具体细节,官方文档中有详细描述:

https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html

2、在 build.gradle 中指明版本

要在 build.gradle  中,明确指定添加的是 com.android.support:support-v4:27.0.2。这将让Gradle 覆盖旧版本。

  1. dependencies { 
  2.     implementation fileTree(dir: 'libs', include: ['*.jar']) 
  3.     implementation 'com.android.support.constraint:constraint-layout:1.0.2' 
  4.     // To resolve the conflict for com.android.databinding:library:1.3.1 
  5.     // dependency on support-v4:21.0.3 
  6.     implementation 'com.android.support:support-v4:27.0.2' 
  7.     implementation 'com.android.support:appcompat-v7:27.0.2' 

对我来说,在 build.gradle 中显式添加依赖关系似乎更加的自然,并且可以留下注释。当我们再次更新库来检查它是否仍然需要显式添加时,这个注释将提醒我关注它。

一旦添加并进行项目同步之后,错误文本将消失。现在,如果我们再次运行依赖关系命令,我们将看到support-v4:21.0.3解决-> 27.0.2。

大部分时候 Gradle 会正确解决依赖关系。而了解了 Gradle 的依赖关系,我想遇到这样的问题我们应该更清楚如何去解决它。

【本文为51CTO专栏作者“张旸”的原创稿件,转载请通过微信公众号联系作者获取授权】

戳这里,看该作者更多好文

【编辑推荐】

  1. Spring Cloud实战小贴士:Zuul统一异常处理(一)
  2. Spring Cloud实战小贴士:Zuul统一异常处理(二)
  3. 海量日志中,如何实时在线检测未知异常行为?看瀚思的序列异常算法
  4. Spring Cloud实战小贴士:Zuul统一异常处理(三)
  5. 像npm一样在Andriod项目中引入Gradle依赖
【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

热门职位+更多