#.Gradle依赖配置

##.Gradle依赖管理与两个重要的classpath相关,每个Module都有:

1.编译时路径:compileClasspath

编译时能使用的代码,当一个类参与编译时,Gradle会将其放在compileClasspath中;
编译过程会将源代码编译为.class文件。

2.运行时路径:runtimeClasspath

运行时使用的代码,当一个类参与打包时,Gradle就会将其放在runtimeClasspath中;
运行时会将编译好的.class文件在JVM上运行。
各种不同依赖方式的关键区别就是:依赖树上的直接依赖包、间接依赖包的代码,是否允许加入编译时路径、运行时路径,或者是二者都允许加入。

Gradle3.0以后常用的关键字有implementation、api、compileOnly

1.implementation

与Gradle2.0的compile对应,会将直接依赖包同时添加到编译时路径、运行时路径,依赖包会被打入输出包中(aar或apk)。 差别在于对间接依赖包的处理上,使用implementation时直接依赖包不会向上层传递自己内部的依赖关系。   
举例,A依赖B,B依赖C。
对于A而言:B会同时加入A的编译时路径、运行时路径;但C不会加入A的编译时路径,只会加入A的运行时路径。
因此,A在编译时只能访问B对外暴露的类和接口,不能访问C对外暴露的类和接口。因为B、C加入A的的运行时路径,所以对A打包时,B、C会打到A的输出包中。
因为A不能直接访问C中的代码,所以修改C中代码时,只会影响直接依赖它的B,不会影响到更上层。所以重新对A打包时,只需要对C、B重新编译,不需要对A重新编译。
当有很多Module相互依赖,全部使用implementation时,修改一个Module,只有直接依赖它的Module受影响,绝大部分Module不需要重新编译,会显著提升构建时间。 一般建议配置依赖关系时尽可能使用implementation,而非api。

2.api

与Gradle2.0的compile对应,功能完全一样,会将直接依赖包和间接依赖包同时添加到编译时路径、运行时路径,并且会将依赖包依赖包会被打入输出包中(aar或apk)。 与 Gradle2.0的compile相同 , 编译时直接依赖包会向上层传递自己内部的依赖关系。
举例,A依赖B,B依赖C。
对于A而言:B、C会同时加入A的编译时路径、运行时路径。
因此,A在编译时既能访问B对外暴露的类和接口,也能访问C对外暴露的类和接口。因为B、C加入A的的运行时路径,所以对A打包时,B、C会打到A的输出包中。
A能直接访问C中的代码,在编写代码调用时是方便了一些,但代价是修改C中对外暴露的代码时,不仅B受影响,A也受影响。所以重新对A打包时,C、B、A都需要重新编译。
当有很多Module相互依赖,全部使用api时,修改一个Module对外暴露的代码时,所有直接依赖它和间接依赖它的Module都受影响。如果修改的是依赖树较低层位置的Module,可能绝大部分Module后继都需要重新编译,构建时间会大大增加。 一般建议配置依赖关系时尽可能使用implementation,而非api。

3.compileOnly

与Gradle2.0的provided对应,依赖包只添加到编译时路径,不会添加到运行时路径,因此编译时可用,但不会打包到输出包中(aar或apk)。
这可以减少输出包的体积,在只有编译时需要,运行时可选的情况下,很有用。例如可通过网络动态下载所需依赖包时,依赖包事先可不必打包到输出包里,当判断需要用到相关模块时,可以再下载。

4.runtimeOnly

与apk对应,依赖包不添加到编译时路径,只会添加到运行时路径,因此编译时不可用,但最终会打包到输出包中(aar或apk)。(没用过)

Gradle新老版本关键字对应一览表:

Gradle3.x+版本配置

已弃用配置(2.0及以前)

api

compile

implement

compile

compileOnly

provided

runtimeOnly

apk

testImplementation

testCompile

androidTestImplementation

androidTestCompile

debugImplementation

debugCompile

releaseImplementation

releaseCompile

#.Gradle依赖冲突的出现与解决

1.依赖冲突出现的原因:

Android项目中有多个有相互依赖关系的Module,每个Module都依赖多个库(既可以是第三方库,也可以是Module打包成的aar等)。

Gradle会按照配置的依赖关系按照树形结构来做依赖解析,当发现依赖树中出现了同一个库的不同版本(意味着同一个库的不同实现代码),就会出现依赖冲突。

(默认情况下Gradle会尝试帮我们解决依赖冲突,解决的方式是使用最新的版本;这里的最新不是判断版本号大小,应该是根据发布时间来决定!没细究过其具体解决依赖冲突的方式。)

例:考虑如下场景:A 模块依赖 B1 和 C, D 模块依赖了 B2,其中 B1 和 B1 是同一个Module B的两个不同版本;同时,工程中我们同时依赖了 A 和 D。这种情况下,会存在针对Module B的依赖冲突!

2.依赖冲突的解决

2.1最好的方式,当然是依赖库不出现版本冲突。

可以自己写一个gradle脚本,例如上文中的utils.gralde,统一管理项目中用到的所有库的版本。

所有用到这些库的地方,统一都使用脚本中定义好的版本。

2.2通过transitive、exclude等关键字手动配置,解决冲突

1)transitive关键字:

对某个依赖库设置transitive关键字后,Gradle在解析依赖树时不会对该库内部的依赖关系做解析。

2)exclude关键字:

exclude关键字可以解除对依赖库内部的指定部分库的依赖解析。

3)force关键字:

force关键字可以强制设置指定Module依赖某个库。

示例,针对上面的依赖冲突示例,避免B1与B2的冲突:

(1) 方案一:针对 A 或 D 配置 transitive。

这里针对A配置,不解析A模块的传递依赖,因此当前Module的依赖关系树中不再包含 B1 和 C,这里需要手动添加依赖 C

dependencies {

implementation A {

transitive = false

}

implementation C

implementation D {

//transitive = false

}

}

(2) 方案二:针对 A 或 D 配置 exclude规则,此处针对A配置,依赖关系树中不再包含B1

dependencies {

implementation A {

exclude  B1

}

implementation D {

//exclude  B2

}

}

(3) 方案三:使用force强制依赖某个版本,如强制依赖 B1 或者 B2

以下是在顶层build.gradle中配置,强制所有module依赖B1

configurations.all {

resolutionStrategy {

force B1

// force B2

}

}

##.个人推荐的依赖配置方式

可以自己写一个gradle脚本,例如上文中的utils.gralde,统一管理项目中用到的所有第三方库的版本。

所有用到第三方库的地方,统一都使用脚本中定义好的版本。

至于自己写的Module,使用implementation方式,只对它直接用到的Module设置依赖关系(不要设置transitive=false,否则要把这些直接依赖包内部的包也统统设置到当前Module)。

这些可以尽可能少的配置依赖关系,而且只要直接依赖包的对外类、接口不变,无论依赖树上子孙节点内部如何修改,都不用重新编译当前包。修改代码时,需要重新编译的包较少,提高编译效率。

Android Gradle依赖配置与依赖冲突解决相关推荐

  1. maven依赖管理(依赖配置、依赖传递、依赖冲突、依赖范围)

    文章目录 基本说明 依赖配置 依赖传递 直接依赖 间接依赖 依赖冲突 路径优先 声明优先 特殊依赖 可选依赖 排除依赖 可选依赖和排除依赖区别 依赖范围 总结 基本说明 这篇文章会介绍在maven中的 ...

  2. Maven的传递性依赖及其jar包冲突解决

    一.Maven简介 Maven是一个跨平台的项目管理工具.作为Apache组织的一个颇为成功的开源项目,其主要服务于基于Java平台的项目创建,依赖管理和项目信息管理. 二.Maven的依赖管理 1. ...

  3. Android Gradle进阶配置指南

    简单的总结一下gradle: 1.Gradle是一种构建工具,它可以帮你管理项目中的差异,依赖,编译,打包,部署......你可以定义满足自己需要的构建逻辑,写入到build.gradle中供日后复用 ...

  4. Android Gradle进阶配置指南 1

    简单的总结一下gradle: 1.Gradle是一种构建工具,它可以帮你管理项目中的差异,依赖,编译,打包,部署......你可以定义满足自己需要的构建逻辑,写入到build.gradle中供日后复用 ...

  5. maven工程导入项目打开404_Maven依赖配置和依赖范围

    教程前面用坐标一一对应地描述了构件,并且保存在仓库中了.那用坐标描述好后,把它们放在仓库中的作用是什么呢?当其他项目需要在这些构件的基础上做开发的时候,用户就没必要自己再重新实现一遍了.直接指定坐标, ...

  6. Maven依赖配置和依赖范围

    文章目录 1.美图 2.参考 3.概述 4.依赖的配置 5.依赖的范围 5.1 compile 5.2 test 5.3 provided 5.4 runtime 5.5 system 5.6 imp ...

  7. Android Gradle 的配置从 Groovy 迁移到 KTS

    目录 #1. 引用 #2.常用术语 #3.脚本文件命名 #4.Gradle迁移示例 1.准备工作:对 Groovy 做简单转换 2. plugins 代码块迁移 3. 显式和隐式 buildTypes ...

  8. Maven依赖配置、依赖传递和依赖范围。

    一.依赖传递. 依赖具有传递性: 1.直接依赖:在当前项目中通过依赖配置建立的依赖关系. 2.间接依赖:被资源的资源如果依赖其他资源,当前项目简介依赖其他资源. 3.依赖传递冲突问题: 路径优先:当依 ...

  9. 交换机配置初始IP冲突解决方法

    Primary IP address conflict 的解决方法: 举个例子:当掩码设置为16位时,我将3/1口的IP地址设置为192.16.20.1/16,3/2口的IP地址设置为192.16.3 ...

最新文章

  1. mysql noinstall_windows mysql noinstall
  2. IT项目之旅(二)篮球计分器(分析、设计、实现)
  3. 刘志勇:微博短视频百万级高并发架构
  4. chart控件做实时曲线显示_Python 如何实时绘制数据
  5. 【操作系统】使用循环创建线程,一个手残导致的bug
  6. CruiseControl.NET与TFS结合的配置文件
  7. java 程序流程控制知识点_JAVA基础知识点梳理三:流程控制语句
  8. splObjectStroge的作用,实例化一个数组
  9. 信度和效度经典例子_浅析经典目标检测评价指标--mmAP(一)
  10. 情怀再次输给现实!中国式星巴克,如今亏到连租金都交不起
  11. 浅谈css中一个元素如何在其父元素居中显示
  12. Life is not fair, get used to it.
  13. 电力系统matlab实验报告,电力系统分析潮流实验报告
  14. 深度解析,马斯克最新发射的先进火箭
  15. Image Tampering Detection via Semantic Segmentation Network
  16. 租车还能这么玩?快来看看神州租车
  17. 移动架构之MVP框架
  18. 如何替换 JavaScript 中所有出现的字符串
  19. 现代科技沃土滋养下的数据黑市和网络犯罪
  20. Java 三大器之监听器Listener

热门文章

  1. java web 面包屑,自动面包屑 Headers
  2. Windows虚拟键盘码
  3. 基因组变异对于 ceRNA 调控影响的数据库LnCeVar使用方法
  4. flex 跨域访问问题
  5. MM ABAP采购资讯记录批量删除
  6. 如何在笔记本上将地图缩小_如何在任何计算机上将iPad用作辅助显示器
  7. “新燕窝”时代,黑历史与生命力共存的燕窝经济
  8. 微信群运营7大运营要点,了解一下?
  9. [IL2CPP] 我在读取 IL2CPP 输出时遇到的三个惊喜
  10. 数据压缩(三)——AVI文件分析WAV文件分析