[toc]
Android 开发常见的gradle 依赖包相关的问题有如下:
Android 开发常见 Gradle 问题
- 如何查看项目里面引入的某个依赖包,具体是由哪个三方库引入的?
- 问题场景1,多版本依赖:项目里面某个库存在多个版本,导致编译冲突,如何查看某个版本的库是由谁引入的 ?
- 问题场景2,相同版本重复依赖:相同的依赖包,被重复引入。某些第三方库提供时内部已经集成了部分依赖库,接入方在接入时,同时引入了该版本的库。
- 解决参看:解决问题1
- gradle 下载慢问题如何解决?
- 解决参看:gradle 下载慢问题
- gradle 下载的依赖包存放位置在哪儿,如何手动管理?
1. 查看 Gradle 项目包依赖关系
命令总结:
gradle :app:dependencies --configuration debugCompileClasspath > de.txt
为了解决问题1, 我们需要知道如何查看项目里的依赖关系,可以通过gradle命令查看:
// 开发环境已经配置gradle环境变量时直接使用gradle,模块名替换成项目中的模块名如 app
gradle :模块名:dependencies > de.txt
上述命令,将指定模块的依赖关系,输出到 de.txt文件中,若环境中没有配gradle环境变量,也可以使用项目里面的graldew ,效果是一样的:
// 若无法执行,可先给 graldew 加可执行权限:chmod +x gradlew
./graldew :模块名:dependencies > de.txt
1.1 gradle :app:dependencies --configuration debugCompileClasspath
打开 de.txt,里面会根据不同的编译模式,输出相应的依赖关系,例如有:
debugAndroidTestCompileClasspath - Compile classpath for compilation 'debugAndroidTest' (target (androidJvm)).
debugCompileClasspath - Compile classpath for compilation 'debug' (target (androidJvm)).
debugUnitTestCompileClasspath - Compile classpath for compilation 'debugUnitTest' (target (androidJvm)).
releaseCompileClasspath - Compile classpath for compilation 'release' (target (androidJvm)).
releaseUnitTestCompileClasspath - Compile classpath for compilation 'releaseUnitTest' (target (androidJvm)).
...
这里,我们重点关注 debugCompileClasspath(即 debug下的依赖关系) 与 releaseCompileClasspath(即 release下的依赖关系)。
我们还可以通过加过滤参数 --configuration 编译模式 ,只关注对应编译模式下的依赖关系,例如:
gradle :app:dependencies --configuration debugCompileClasspath > de.txt
- app module 的build.gradle如下 :
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" implementation "androidx.core:core-ktx:${androidx_core_ktx}" implementation "androidx.appcompat:appcompat:${androidx_appcompat}" implementation "androidx.constraintlayout:constraintlayout:${androidx_constraintlayout}" implementation "com.google.android.material:material:${material}" implementation "com.alibaba:arouter-api:${arouter}" annotationProcessor "com.alibaba:arouter-compiler:${arouter}" kapt "com.alibaba:arouter-compiler:${arouter}" implementation project(":lib_order") implementation project(":lib_pay") - 得到的依赖结果以
debugCompileClasspath为例,如下:debugCompileClasspath - Compile classpath for compilation 'debug' (target (androidJvm)). +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72 | \--- org.jetbrains:annotations:13.0 +--- androidx.core:core-ktx:1.3.2 | +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.71 -> 1.3.72 (*) | +--- androidx.annotation:annotation:1.1.0 | \--- androidx.core:core:1.3.2 | +--- androidx.annotation:annotation:1.1.0 | +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.1.0 | | +--- androidx.lifecycle:lifecycle-common:2.1.0 | | | \--- androidx.annotation:annotation:1.1.0 | | +--- androidx.arch.core:core-common:2.1.0 | | | \--- androidx.annotation:annotation:1.1.0 | | \--- androidx.annotation:annotation:1.1.0 | \--- androidx.versionedparcelable:versionedparcelable:1.1.0 | +--- androidx.annotation:annotation:1.1.0 | \--- androidx.collection:collection:1.0.0 -> 1.1.0 | \--- androidx.annotation:annotation:1.1.0 +--- androidx.appcompat:appcompat:1.2.0 | +--- androidx.annotation:annotation:1.1.0 | +--- androidx.core:core:1.3.0 -> 1.3.2 (*) | +--- androidx.cursoradapter:cursoradapter:1.0.0 | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | +--- androidx.fragment:fragment:1.1.0 | | +--- androidx.annotation:annotation:1.1.0 | | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | | +--- androidx.collection:collection:1.1.0 (*) | | +--- androidx.viewpager:viewpager:1.0.0 | | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | | +--- androidx.core:core:1.0.0 -> 1.3.2 (*) | | | \--- androidx.customview:customview:1.0.0 | | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | | \--- androidx.core:core:1.0.0 -> 1.3.2 (*) | | +--- androidx.loader:loader:1.0.0 | | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | | +--- androidx.core:core:1.0.0 -> 1.3.2 (*) | | | +--- androidx.lifecycle:lifecycle-livedata:2.0.0 | | | | +--- androidx.arch.core:core-runtime:2.0.0 | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | | | | \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*) | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 | | | | | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.1.0 (*) | | | | | +--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*) | | | | | \--- androidx.arch.core:core-runtime:2.0.0 (*) | | | | \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*) | | | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 | | | \--- androidx.annotation:annotation:1.1.0 | | +--- androidx.activity:activity:1.0.0 | | | +--- androidx.annotation:annotation:1.1.0 | | | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | | | +--- androidx.lifecycle:lifecycle-runtime:2.1.0 (*) | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.1.0 (*) | | | \--- androidx.savedstate:savedstate:1.0.0 | | | +--- androidx.annotation:annotation:1.1.0 | | | +--- androidx.arch.core:core-common:2.0.1 -> 2.1.0 (*) | | | \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.1.0 (*) | | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 (*) | +--- androidx.appcompat:appcompat-resources:1.2.0 | | +--- androidx.annotation:annotation:1.1.0 | | +--- androidx.core:core:1.0.1 -> 1.3.2 (*) | | +--- androidx.vectordrawable:vectordrawable:1.1.0 | | | +--- androidx.annotation:annotation:1.1.0 | | | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | | | \--- androidx.collection:collection:1.1.0 (*) | | \--- androidx.vectordrawable:vectordrawable-animated:1.1.0 | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) | | +--- androidx.interpolator:interpolator:1.0.0 | | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | \--- androidx.collection:collection:1.1.0 (*) | \--- androidx.drawerlayout:drawerlayout:1.0.0 | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | +--- androidx.core:core:1.0.0 -> 1.3.2 (*) | \--- androidx.customview:customview:1.0.0 (*) +--- androidx.constraintlayout:constraintlayout:2.0.4 | +--- androidx.appcompat:appcompat:1.2.0 (*) | +--- androidx.core:core:1.3.1 -> 1.3.2 (*) | \--- androidx.constraintlayout:constraintlayout-solver:2.0.4 +--- com.google.android.material:material:1.3.0 | +--- androidx.annotation:annotation:1.0.1 -> 1.1.0 | +--- androidx.appcompat:appcompat:1.1.0 -> 1.2.0 (*) | +--- androidx.cardview:cardview:1.0.0 | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | +--- androidx.coordinatorlayout:coordinatorlayout:1.1.0 | | +--- androidx.annotation:annotation:1.1.0 | | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | | +--- androidx.customview:customview:1.0.0 (*) | | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) | +--- androidx.constraintlayout:constraintlayout:2.0.1 -> 2.0.4 (*) | +--- androidx.core:core:1.2.0 -> 1.3.2 (*) | +--- androidx.dynamicanimation:dynamicanimation:1.0.0 | | +--- androidx.core:core:1.0.0 -> 1.3.2 (*) | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) | | \--- androidx.legacy:legacy-support-core-utils:1.0.0 | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | +--- androidx.core:core:1.0.0 -> 1.3.2 (*) | | +--- androidx.documentfile:documentfile:1.0.0 | | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | +--- androidx.loader:loader:1.0.0 (*) | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 | | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | | \--- androidx.print:print:1.0.0 | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0 | +--- androidx.annotation:annotation-experimental:1.0.0 | +--- androidx.fragment:fragment:1.0.0 -> 1.1.0 (*) | +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.1.0 (*) | +--- androidx.recyclerview:recyclerview:1.0.0 -> 1.1.0 | | +--- androidx.annotation:annotation:1.1.0 | | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | | +--- androidx.customview:customview:1.0.0 (*) | | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) | +--- androidx.transition:transition:1.2.0 | | +--- androidx.annotation:annotation:1.1.0 | | +--- androidx.core:core:1.0.1 -> 1.3.2 (*) | | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) | \--- androidx.viewpager2:viewpager2:1.0.0 | +--- androidx.annotation:annotation:1.1.0 | +--- androidx.fragment:fragment:1.1.0 (*) | +--- androidx.recyclerview:recyclerview:1.1.0 (*) | +--- androidx.core:core:1.1.0 -> 1.3.2 (*) | \--- androidx.collection:collection:1.1.0 (*) +--- com.alibaba:arouter-api:1.5.1 | \--- com.alibaba:arouter-annotation:1.0.6 +--- project :lib_order +--- project :lib_pay +--- org.jetbrains.kotlin:kotlin-stdlib:{strictly 1.3.72} -> 1.3.72 (c) +--- androidx.core:core-ktx:{strictly 1.3.2} -> 1.3.2 (c) +--- androidx.appcompat:appcompat:{strictly 1.2.0} -> 1.2.0 (c) +--- androidx.constraintlayout:constraintlayout:{strictly 2.0.4} -> 2.0.4 (c) +--- com.google.android.material:material:{strictly 1.3.0} -> 1.3.0 (c) +--- com.alibaba:arouter-api:{strictly 1.5.1} -> 1.5.1 (c) +--- org.jetbrains.kotlin:kotlin-stdlib-common:{strictly 1.3.72} -> 1.3.72 (c) +--- org.jetbrains:annotations:{strictly 13.0} -> 13.0 (c) +--- androidx.annotation:annotation:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.core:core:{strictly 1.3.2} -> 1.3.2 (c) +--- androidx.cursoradapter:cursoradapter:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.fragment:fragment:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.appcompat:appcompat-resources:{strictly 1.2.0} -> 1.2.0 (c) +--- androidx.drawerlayout:drawerlayout:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.constraintlayout:constraintlayout-solver:{strictly 2.0.4} -> 2.0.4 (c) +--- androidx.cardview:cardview:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.coordinatorlayout:coordinatorlayout:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.dynamicanimation:dynamicanimation:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.annotation:annotation-experimental:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.lifecycle:lifecycle-runtime:{strictly 2.1.0} -> 2.1.0 (c) +--- androidx.recyclerview:recyclerview:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.transition:transition:{strictly 1.2.0} -> 1.2.0 (c) +--- androidx.vectordrawable:vectordrawable:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.viewpager2:viewpager2:{strictly 1.0.0} -> 1.0.0 (c) +--- com.alibaba:arouter-annotation:{strictly 1.0.6} -> 1.0.6 (c) +--- androidx.versionedparcelable:versionedparcelable:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.collection:collection:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.viewpager:viewpager:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.loader:loader:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.activity:activity:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.lifecycle:lifecycle-viewmodel:{strictly 2.1.0} -> 2.1.0 (c) +--- androidx.vectordrawable:vectordrawable-animated:{strictly 1.1.0} -> 1.1.0 (c) +--- androidx.customview:customview:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.legacy:legacy-support-core-utils:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.lifecycle:lifecycle-common:{strictly 2.1.0} -> 2.1.0 (c) +--- androidx.arch.core:core-common:{strictly 2.1.0} -> 2.1.0 (c) +--- androidx.lifecycle:lifecycle-livedata:{strictly 2.0.0} -> 2.0.0 (c) +--- androidx.savedstate:savedstate:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.interpolator:interpolator:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.documentfile:documentfile:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.localbroadcastmanager:localbroadcastmanager:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.print:print:{strictly 1.0.0} -> 1.0.0 (c) +--- androidx.arch.core:core-runtime:{strictly 2.0.0} -> 2.0.0 (c) \--- androidx.lifecycle:lifecycle-livedata-core:{strictly 2.0.0} -> 2.0.0 (c)
通过上述依赖关系结构结果,我们找到需要关注的依赖包,以及最终依赖包的版本,即可解决依赖冲突、重复引入依赖包等问题。
1.2 Gradle 3种编译依赖模式 implementation、compileOnly、api 与问题
假设我们写了一个 lib module:myLib,依赖了 okhttp3库,我们有3种依赖 okhttp3 库的方式
- implementation
- 仅内部使用 声明式依赖,不传递依赖关系,只在模块内部使用被依赖的 okhttp3 api,接入方无需再次引入 okhttp3;
- 若接入方也声明依赖了 okhttp3 版本,gradle 将自动使用最高版本进行项目编译
- compileOnly
- 仅参与编译 声明式依赖,同
implementation,与其唯一区别,接入方在使用myLib时,必须引入被依赖的库,即声明implementation "com.squareup.okhttp3:okhttp:${okhttp3}",否则报错
- 仅参与编译 声明式依赖,同
- api
- 打包依赖,会传递依赖关系,相关api,会直接打包进入输出sdk中。
implementation与compileOnly都只是声明依赖,不会将被依赖对象打包输出到编译产物中。
使用场景:
- api: 一般在项目分层中的较底层使用,暴露底层接口给上层,上层不需要重复声明依赖底层库
- compileOnly:一般用于 sdk 设计时,需要用到第三方库,而又不想集成到到sdk中输出,同时接入时,强制要求接入方必须显示接入该sdk 中依赖的库才可正常使用
- implementation:一般除上述场景:应用的app module、sdk设计输出无需接入方显示引入内部依赖库等。
1.3 关于重复依赖与多版本依赖
+--- androidx.appcompat:appcompat:1.2.0
| +--- androidx.annotation:annotation:1.1.0
| +--- androidx.core:core:1.3.0 -> 1.3.2 (*)
| +--- androidx.cursoradapter:cursoradapter:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
...
上述含义:appcompat: 1.2.0 编译,依赖 annotation:1.1.0、core:1.3.0、cursoradapter:1.0.0、...包 而 cursoradapter:1.0.0 编译又依赖 annotation:1.0.0 , 这时 gradle 自动将使用高版本 annotation:1.1.0 。
- 通过声明依赖的方式,gradle会自动处理重复依赖问题,并且对于同一个库的不同版本,gradle会自动使用最新版本来进行依赖替换、编译
- 而如果是sdk 库再输出的时候,用的是打包依赖,即
api方式,则会在输出时,内置依赖的第三方库,gradle无法再自动使用最新版本来处理,照成依赖冲突问题
1.4 exclude 排除三方库中引入的依赖包
exclude 排除三方库中引入的依赖包主要用法有以下两种,根据实际情况,使用一种即可
implementation ("groupName:moduleName:XXX") {
// exclude group: 'com.android.support'
exclude group: 'com.android.support', module: 'support-compat'
}
1.5 解决问题1
回答文章开头的问题1, 要解决主要有两种思路。
- sdk 输出方,设计原则
- 尽量避免内部集成第三方库输出,即不要采用
api方式 或者 直接 include jar 方式,而要使用compileOnly或implementation声明依赖的方式,去依赖第三方库
- 尽量避免内部集成第三方库输出,即不要采用
- sdk 接入方,接入原则
- 接入sdk时,遇到依赖冲突问题,先查看依赖关系:
gradle :app:dependencies --configuration debugCompileClasspath > de.txt,找到引入冲突包的引入点,在其上exclude掉重复引入的库。
- 接入sdk时,遇到依赖冲突问题,先查看依赖关系:
2. gradle 下载慢问题
使用aliyun maven 镜像即可解决部分依赖库下载慢问题,具体配置参考官方网站。
配置思路有两种:全局配置和当前工程配置。
官方主要是对当前工程进行配置生效,我们若有需要对所有工程生效,还可将官方配置文件,放到用户的gradle 目录,MAC 下即 cd ~/.gradle, 新建init.gradle,放置上述配置内容即可。
3. gradle cache 目录结构
3.1 gradle顶级目录
gradle 本身路径:UserHome/.gradle,其目录下有:
- caches:gradle缓存目录
- daemon: daemon日志目录
- native: gradle平台相关目录
- wrapper:gradle-wrapper下载目录
3.2 caches 目录
caches 本身路径:UserHome/.gradle/caches,其目录下有:
- 2.14.1::gradle程序的脚本(gradle程序版本) ...
- 6.6.1:gradle程序的脚本(gradle程序版本)
- jars-2
- jars-3
- jars-8
- journal-1
- modules-2 : 下载缓存目录
- transforms-1
- transforms-2
3.3 caches/modules-2 目录
modules-2 本身路径:UserHome/.gradle/caches/modules-2,其目录下有: files-2.1:gradle下载的jar/aar目录
3.4 files-2.1的目录组织(jar/aar都下载到这里)
files-2.1本身路径:UserHome/.gradle/caches/modules-2/files-2.1,其目录下有:
${org}/${package}/${version}/${shanum1}/${package-version}.pom
${org}/${package}/${version}/${shanum2}/${package-version}.jar
${org}/${package}/${version}/${shanum3}/${package-version}-sources.jar
${org}/${package}/${version}/${shanum4}/${package-version}-javadoc.jar
3.5 手动下载依赖库 (aar/jar) 替换gradle cache 缓存
下面以okhttp3为例,如何手动下载该依赖包,替换到gradle cache中
-
访问okhttp3 指定版本maven仓库:repo1.maven.org/maven2/com/…
okhttp-3.10.0-javadoc.jar 2018-02-24 18:35 352538 okhttp-3.10.0-javadoc.jar.asc 2018-02-24 18:35 833 okhttp-3.10.0-javadoc.jar.md5 2018-02-24 18:35 32 okhttp-3.10.0-javadoc.jar.sha1 2018-02-24 18:35 40 okhttp-3.10.0-sources.jar 2018-02-24 18:35 314424 okhttp-3.10.0-sources.jar.asc 2018-02-24 18:35 833 okhttp-3.10.0-sources.jar.md5 2018-02-24 18:35 32 okhttp-3.10.0-sources.jar.sha1 2018-02-24 18:35 40 okhttp-3.10.0.jar 2018-02-24 18:35 412117 okhttp-3.10.0.jar.asc 2018-02-24 18:35 833 okhttp-3.10.0.jar.md5 2018-02-24 18:35 32 okhttp-3.10.0.jar.sha1 2018-02-24 18:35 40 okhttp-3.10.0.pom 2018-02-24 18:35 2302 okhttp-3.10.0.pom.asc 2018-02-24 18:35 833 okhttp-3.10.0.pom.md5 2018-02-24 18:35 32 okhttp-3.10.0.pom.sha1 2018-02-24 18:35 40 -
访问其中的 okhttp-3.10.0.jar.sha1 ,获取
jar包的sha1值为:7ef0f1d95bf4c0b3ba30bbae25e0e562b05cf75e -
以
sha1值 7ef0f1d95bf4c0b3ba30bbae25e0e562b05cf75e,在本地新建文件夹:UserHome/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.10.0/7ef0f1d95bf4c0b3ba30bbae25e0e562b05cf75e -
下载其中的 okhttp-3.10.0.jar 文件,放入上述文件夹中
-
如果还需要其他文件:
okhttp-3.10.0.pom、okhttp-3.10.0-sources.jar、okhttp-3.10.0-javadoc.jar,重复上述步骤即可。 总结:先获取到对应文件的sha1值,以该值创建文件夹,再将下载的文件放入创建的文件夹中。
4. Gradle 编译输出 aar
// 执行指令后,查看目录:build/outputs/aar/
gradle assemble