先安利一个查询项目依赖的命令:./gradlew 模块名:dependencies 。
一、exclude
用法:exclude group:' ', module: ' ' 【 group和module两个参数可分别单独使用 】
说明:排除某个依赖,可解决部分传递依赖。
使用场景:
- 解决依赖冲突。若两个模块使用相同 jar 包的不同版本,gradle 默认会使用最新版本的 jar 包,此时可以通过 exclude 排除冲突。(版本冲突带来的问题最主要是API类或方法移除。)
- 运行期无需此模块。
- 传递依赖无法找到时,可通过 exclude 排除。
- 版权原因需排除。
compile 'com.android.support:support-v4:26.1.0'
// 单独排除某个模块中的依赖
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') {
exclude group: 'com.android.support'
}
// 排除所有子依赖中的support依赖,统一使用主项目中的版本
configurations {
all*.exclude group: 'com.android.support'
}
用法:主工程使用的 support 包版本为 26.1.0,使用 exclude group: 'com.android.support' 可以将 advrecyclerview 模块中的 support 排除掉,统一使用主工程的 v26.1.0 版本。不管advrecyclerview依赖的该support包版本时高于还是低于主工程版本。
假设 advrecyclerview 中依赖的 support相关版本为 27.0.0,排除依赖前,项目依赖关系为:
project :shop
| + - com.android.support:appcompat-v7:26.1.0 ()
| + - com.android.support:support-v4:26.1.0 ()
| + - com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0
| | + - - - com.android.support:appcompat-v7:27.0.0 -> 26.1.0 ()
| | \ - - - com.android.support:recyclerview-v7:27.0.0 -> 26.1.0
| | + - - - - - com.android.support:support-annotations:26.1.0
| | + - - - - - com.android.support:support-compat:26.1.0 ()
| | \ - - - - - com.android.support:support-core-ui:26.1.0 (*)
对应的在build后,External Libraries 中会同时存在 support v27.0.0 和 v26.1.0 两种版本的aar依赖。
排除 support 依赖后,External Libraries 就只会存在 v26.1.0 版本的aar。对应的依赖关系如下:
project :shop
| + - com.android.support:appcompat-v7:26.1.0 ()
| + - com.android.support:support-v4:26.1.0 ()
| + - com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0
二、transitive
用法:transitive = true | false
说明:是否传递本身的依赖给宿主程序(使用传递依赖时,Gradle 会将传递依赖一起下载下来。compile 默认是开启传递依赖)
// 统一指定 transitive
configurations.all {
transitive = false
}
// 单独指定依赖项的 transitive
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') {
transitive = false
}
transitive = true,依赖同于没有使用 exclude 排除依赖 ,每个包的依赖项都会被递归分析并添加进来。
transitive = false,则依赖关系同于用 exclude 排除依赖。
Tips: exclude 和 transitive 可以同时使用,exclude会排除 transitive=true时的一些传递依赖。
三、force
用法:force = true
作用:强制使用某个版本。出现冲突时,优先使用该版本解决。
// 强制使用 support-v4 26.1.0版本
compile('com.android.support:support-v4:26.1.0') {
force = true
}
四、动态版本(不建议使用)
使用场景:保持工程依赖都是最新版本。
使用方式:+,可以让gradle每次构建时检查远程仓库是否存在最新版本,若存在则下载。也可指定某个大版本下的最新子版本,1.+,表示始终依赖最新的 1.x 版本。
compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.+'
缺点:
- 减低构建速度并且会提高构建失败风险;
- 新版本可能带来兼容性问题。
五、综合实例
compile('org.hibernate:hibernate:3.1') {
// 冲突时优先使用该版本
force = true
// 依据构建名称排除
exclude module: 'cglib'
// 依据组织名称排除
exclude group: 'org.jmock'
// 依据组织名称+构件名称排除
exclude group: 'org.unwanted', module: 'iAmBuggy'
// 为本依赖关闭依赖传递特性
transitive = false
}
六、问题
1.项目中多个模块依赖同一个依赖 D 的不同版本,如何保持每个模块直接使用自己本身 compile 的依赖版本呢?
A:如果是直接 compile 包含不同版本的依赖,会造成依赖冲突。有一种方式可以直接将模块打包成本地 jar 。打包成本地 aar 文件,也是不行,因为本地 aar 依赖,需要外部也 compile aar 中依赖的一些架包,否则会找不到。
另一种方式就很有效保证 各个模块保持自己依赖的版本,而不用在意其他版本并且担心产生冲突。具体如下:
configurations.all {
// 遍历所有的依赖,根据 moduleName 使用对应的版本。确实可行
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (requested.name.startsWith("multidex")) {
details.useVersion '26.1.0'
} else if (requested.name.startsWith("advrecyclerview")) {
details.useVersion '27.0.0'
} else {
details.useVersion '25.3.0'
}
}
}
}
七、本地aar依赖问题
场景:主工程app -> shop模块 -> 依赖本地aar
问题:在主工程依赖 shop 模块的远程依赖时,无法找到依赖的本地 aar 相关。
解决:将 本地 aar 放到远端,也是用远程依赖。
原因:主要在于Android 3.0 后本地 aar 依赖无法越级传递依赖。可以看远端 shop模块 maven打包时生成的 .pom 文件,查看具体依赖,发现gradle 会把本地 aar 依赖也当做一份远端依赖进行配置,但是没有group等信息,如此在主工程中依赖 shop 模块是,直接编译不通过,因为会视为远端仓库的依赖,但实际并不存在。(根本原因未知)
问题:本地 jar 依赖和 本地 aar 依赖区别。
- jar 文件只包含编译好的 .class 文件和清单文件,不包含资源文件。所以如果没有 res 资源文件,可以在打包时,将 packaging 配置为 jar 格式;
- aar 文件包含 class 以及 /res 目录下的所有资源文件。
-查看 gradle 下载的远程依赖区别就很明显: