Gradle 依赖统一管理方案和问题排查

Gradle 依赖统一管理方案和问题排查

背景

在组件化开发 Android 应用时,由于多个模块由不同同事负责,并且依赖引入也不是由同一个人来控制,会导致引用到的依赖版本不一致,每个 module 的 api 配置均不一致,会导致调试开发存在很多类似于 Class Not Found 异常或查看源码时多个库版本同时出现,不好短时间内定位问题等等一系列困扰。

尝试统一依赖管理

现在常用的有以下几种方案:

  1. 通过 ExtraPropertiesExtension 来统一管理依赖

将这些依赖统一放在 xxxx.gradle 中,并且在其他的 build.gradle 中使用相同的依赖。

问题:无法自动补全、无法在 Android Studio 中自动跳转等等

  1. 使用 buildSrc 统一管理所有依赖

因为 buildSrc 是具有管理项目中所有其他模块 build.gradle 的属性,并且我们可以使用熟悉的 Kotlin 语言来管理。并且在其他模块的 build.gradle 可以高亮,跳转,提示等等。

使用 buildSrc 管理依赖

创建 buildSrc 及其关联目录、文件

mkdir buildSrc

tree .
|
├─app
├─buildSrc
│  └─src
│      └─main
│          └─kotlin
└─gradle
    └─wrapper
复制代码

创建文件夹后并创建其他相关文件:

1.png

在 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、自动补全

2.png

4、代码高亮

3.png

线上编译平台打包失败问题排查

由于本地能编过,但是线上平台始终编不过,提示报错:

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。

4.png

又联想到最新的 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 多的情况下进行高效管理依赖。

参考资料:

  1. How to manage Gradle dependencies in the Android project proper way
  2. Developing Custom Gradle Plugins
  3. gradle Command-line Interface

猜你喜欢

转载自juejin.im/post/7088157225906077709