从 ext 迁到 Version Catalog:47 个模块的实操记录
buildSrc 里那份 Dependencies.kt 维护了四年,改一个版本号触发全量重编译。迁到 libs.versions.toml 之后,依赖变更不再让 buildSrc 失效。
·581 字 · 约 2 分钟
目录 · 5 节
我们的依赖版本一直放在 buildSrc/src/main/kotlin/Dependencies.kt 里。这个方案在 2022 年是最佳实践,现在它最大的问题是:buildSrc 的任何改动都会让整个构建的配置缓存和编译缓存失效。改一个 androidx.core 的小版本号,等于全量重来。
Version Catalog(gradle/libs.versions.toml)没有这个问题——它是纯数据文件,不参与编译。
迁移前后对比
| buildSrc/Dependencies.kt | libs.versions.toml | |
|---|---|---|
| 改版本号的代价 | buildSrc 重编译 + 全量配置 | 只失效相关模块 |
| IDE 补全 | 有(Kotlin 代码) | 有(Gradle 生成访问器) |
| 跨工程共享 | 需要发布 artifact | from(files(...)) 直接引 |
| 依赖冲突检查 | 无 | bundles + 版本对齐 |
| 学习成本 | 低,就是 Kotlin | 中,TOML 命名有约束 |
命名规则先定死
TOML 的 key 会被转成 Gradle 访问器,-、_、. 都会变成 .。所以 androidx-core-ktx 和 androidx.core.ktx 生成的访问器是同一个,会直接报冲突。
我们定的规则:
- 库的 key 一律用
-分段,形如<group 简写>-<artifact>:androidx-core-ktx、square-okhttp - 版本的 key 用
-连接同一族:androidx-lifecycle、kotlin - 插件的 key 加
plugin-前缀,避免和同名库撞车
[versions]kotlin = "2.2.20"agp = "8.7.3"androidx-lifecycle = "2.9.1"
[libraries]androidx-core-ktx = { module = "androidx.core:core-ktx", version = "1.15.0" }androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
[bundles]lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel"]
[plugins]android-application = { id = "com.android.application", version.ref = "agp" }kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }模块里用起来:
plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android)}
dependencies { implementation(libs.androidx.core.ktx) implementation(libs.bundles.lifecycle) // 一次引一组}迁移脚本
47 个模块手改不现实。我写了个一次性脚本做机械替换,剩下的手工收尾:
#!/usr/bin/env bashset -euo pipefail
# Deps.androidxCoreKtx -> libs.androidx.core.ktxfind . -name "build.gradle.kts" -not -path "./buildSrc/*" -print0 | xargs -0 sed -i -E \ -e 's/Deps\.androidxCoreKtx/libs.androidx.core.ktx/g' \ -e 's/Deps\.okhttp/libs.square.okhttp/g' \ -e 's/Versions\.kotlin/libs.versions.kotlin.get()/g'
./gradlew help --configuration-cache最后那行 help 是有意的:它几乎不做实际工作,但会完整走一遍配置阶段,能立刻暴露替换错的地方,比等 assembleDebug 快得多。
踩到的三处
其一,version.ref 指向不存在的 version key 时,报错信息是 Invalid catalog definition,但不告诉你是哪一条。只能二分注释。
其二,bundles 里的库如果有一个写错,整个 bundle 都不可用,同样不指名。
其三,Renovate / Dependabot 对 TOML 的支持要显式配置 enabledManagers,默认不扫。迁完之后我们有三周没收到任何依赖更新 PR,一直以为是上游没发版。
收益
改一个版本号之后的增量构建:
迁移前:BUILD SUCCESSFUL in 3m 51s (buildSrc 重编译 + 全量配置)迁移后:BUILD SUCCESSFUL in 24s (只重编译受影响模块)这个收益只在「改依赖版本」这个场景成立,日常改业务代码没有差别。但对我们这种每周升一次依赖的节奏,一个月能省下不少时间。
评论
由自建 Waline 驱动