Gradle 依赖统一管理方案和问题排查
背景
在组件化开发 Android 应用时,由于多个模块由不同同事负责,并且依赖引入也不是由同一个人来控制,会导致引用到的依赖版本不一致,每个 module 的 api 配置均不一致,会导致调试开发存在很多类似于 Class Not Found 异常或查看源码时多个库版本同时出现,不好短时间内定位问题等等一系列困扰。
尝试统一依赖管理
现在常用的有以下几种方案:
- 通过 ExtraPropertiesExtension 来统一管理依赖
将这些依赖统一放在 xxxx.gradle 中,并且在其他的 build.gradle 中使用相同的依赖。
问题:无法自动补全、无法在 Android Studio 中自动跳转等等
- 使用 buildSrc 统一管理所有依赖
因为 buildSrc 是具有管理项目中所有其他模块 build.gradle 的属性,并且我们可以使用熟悉的 Kotlin 语言来管理。并且在其他模块的 build.gradle 可以高亮,跳转,提示等等。
使用 buildSrc 管理依赖
创建 buildSrc 及其关联目录、文件
mkdir buildSrc
tree .
|
├─app
├─buildSrc
│ └─src
│ └─main
│ └─kotlin
└─gradle
└─wrapper
创建文件夹后并创建其他相关文件:
在 build.gradle.kts 中写入以下内容:
repositories {
mavenCentral()
}
plugins {
`kotlin-dsl`
}
Deps.kt 写入以下类似内容,像编辑普通 kotlin 类一样:
import java.text.SimpleDateFormat
import java.util.*
object ConfigData {
const val compileSdkVersion = 31
const val minSdkVersion = 21
const val targetSdkVersion = 31
const val versionCode = 5
const val version = "1.2.0"
val versionName by lazy { "V$version build ${buildTime()}" }
//获得当前日期、时间
fun buildTime(): String {
return SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(Date())
}
}
object Lint {
const val quiet = true
const val abortOnError = false
const val ignoreWarnings = true
}
object Versions {
const val gradlePlugin = "7.1.2"
const val kotlin = "1.6.20"
const val kotlinCoroutines = "1.6.0"
const val ktx = "1.7.0"
}
object Deps {
val kotlin by lazy { "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}" }
val ktx by lazy { "androidx.core:core-ktx:${Versions.ktx}" }
}
object BuildPlugins {
val android by lazy { "com.android.tools.build:gradle:${Versions.gradlePlugin}" }
val kotlin by lazy { "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" }
}
添加以上文件之后,sync 之后 build,成功之后就可以在其他 module 中去引用了。
在 build.gradle 文件中引用
1、groovy 文件中替换
minSdk = 19
targetSdk = 31
//替换为
minSdk = ConfigData.minSdkVersion
targetSdk = ConfigData.targetSdkVersion
//在 build.gradle 文件中
implementation 'androidx.core:core-ktx:1.7.0'
//替换为
implementation Deps.INSTANCE.ktx
classpath 'com.android.tools.build:gradle:3.3.0'
//替换为
classpath Deps.BuildPlugins.android
2、kts 文件中替换
implementation("androidx.core:core-ktx:1.7.0")
//替换为
implementation(Deps.INSTANCE.ktx)
3、自动补全
4、代码高亮
线上编译平台打包失败问题排查
由于本地能编过,但是线上平台始终编不过,提示报错:
Build file 'D:\jenkins\workspace\Trans-CCI-Pipeline\12203\buildSrc\build.gradle.kts' line: 8
What went wrong:
Plugin [id: 'org.gradle.kotlin.kotlin-dsl', version: '2.1.6'] was not found in any of the following sources:
主要就是看到找不到 dsl 这个 plugin 库,由于编译服务器和电脑上的区别就在于,编译服务器为了安全考虑无法直连外网,而电脑上却没这个问题,排查方向主要放在了依赖仓库上面。
于是将 build.gradle.kts 文件中的仓库进行了修改
repositories {
~~mavenCentral()~~
maven {
isAllowInsecureProtocol = true
url = uri("--your local proxy--")
}
}
plugins {
`kotlin-dsl`
}
重新尝试在平台上进行打包,依然报同样的错误,增加一下打印
gradlew --info aR
打印多了一些,还是找不到关键的原因,继续增加打印
gradlew --info --stacktrace
这次也只是多了一些异常报错的堆栈,并没有非常明显的异常
* Exception is:
15:15:57 org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'com.gradle.enterprise', version: '3.6.3', artifact: 'com.gradle:gradle-enterprise-gradle-plugin:3.6.3'] was not found in any of the following sources:
15:15:57
15:15:57 - Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
15:15:57 - Plugin Repositories (could not resolve plugin artifact 'com.gradle:gradle-enterprise-gradle-plugin:3.6.3')
15:15:57 Searched in the following repositories:
15:15:57 Gradle Central Plugin Repository
15:15:57 at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.resolveToFoundResult(DefaultPluginRequestApplicator.java:222)
15:15:57 at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.lambda$resolvePluginRequests$4(DefaultPluginRequestApplicator.java:148)
15:15:57 at org.gradle.util.internal.CollectionUtils.collect(CollectionUtils.java:207)
继续增加打印,按照提示使用 —-debug
gradlew -debug --info --stacktrace assembleRelease
但是并没有发现什么更多打印冒出来,于是尝试了一下,只保留 --debug
gradlew -debug assembleRelease
这次打印结果明确了,有多行报错指向一个问题,下载依赖失败了!!!
Attempting to resolve component for org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:2.1.7 using repositories [Gradle Central Plugin Repository]
Loading <https://plugins.gradle.org/m2/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/2.1.7/org.gradle.kotlin.kotlin-dsl.gradle.plugin-2.1.7.pom>
明明已经配置了仓库地址为公司的,为什么还是会去 [plugins.gradle.org/m2](<http://plugins.gradle.org/m2>)
下载呢 ?
经过翻阅 gradle 官方的文档,发现一个提示,建议在 buildSrc 文件夹下面也放置一个哪怕文件内容是空的 setting.gradle.kts。
又联想到最新的 gradle 仓库管理可以通过 setting.gradle.kts
中的 pluginManagement {}
进行管理,于是尝试在 setting.gradle.kts
增加以下内容。
pluginManagement {
repositories {
maven {
isAllowInsecureProtocol = true
url = uri("**---your local repository---**")
}
}
}
再次在编译平台上进行编译,编译成功。
原来在 buildSrc/build.gradle.kts 中指定的仓库依赖,并不是指定 plugin 的,而是指定编译(implementation)的依赖仓库。
总结:
1、不要混用 --info
与 --debug
,他们都是 gradle command 对于日志等级的管理,如果想要最详细的日志,使用 --debug
即可。
2、Project 中的依赖仓库管理,可以通过 root/setting.gradle.kts
来统一管理,而 buildSrc 的插件(plugin)仓库是取决于 buildSrc/setting.gradle.kts
,而不是 buildSrc/build.gradle.kts
。
3、使用 buildSrc、Kotlin Dsl 来统一管理依赖,可以达到代码高亮、自动补全、代码跳转以及依赖更新提示的好处,可以在 module 多的情况下进行高效管理依赖。