Gradle依赖那些事

先安利一个查询项目依赖的命令:./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 下载的远程依赖区别就很明显:
    Gradle依赖那些事_第1张图片

你可能感兴趣的:(Gradle依赖那些事)