Android依赖管理解析:从ext到 Version Catalog的演进
lxx
目次
在 Android 多模块项目中,依赖管理(Dependency Management)往往被低估。
最开始你可能只是写几个 implementation "xxx:xxx:1.0.0",但随着模块数量增长、团队协作增加、版本升级频繁,依赖的统一管理会直接影响项目的可维护性与构建效率。
目前常见的几种依赖管理方式包括:
- 最普通的直接写依赖;
ext 属性集中定义;- 使用
buildSrc 代码模块; - 使用 Gradle 7+ 的版本目录(Version Catalog)。
下面我们从示例、优势与不足的角度,依次剖析这些方案。
直接写依赖 #
最朴素的方式是把依赖写在每个模块的 build.gradle 中。
1
2
3
4
5
6
| dependencies {
implementation("androidx.core:core-ktx:1.10.1")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")
testImplementation("junit:junit:4.13.2")
}
|
优势
- 简单直接,几乎不需要学习成本。
- 适合小型或一次性项目。
- 所有依赖可一眼看清楚。
不足
- 多模块时容易重复定义。
- 升级版本需要全局修改,容易漏。
- 难以审查依赖一致性。
- 无法实现全局统一管理。
这种方式适合 Demo 或临时项目,一旦模块数超过三个,就会让人后悔没早点集中管理。
使用 ext 属性集中管理 #
在根 build.gradle 中用 ext 定义变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ext {
versions = [
coreKtx: "1.10.1",
retrofit: "2.9.0",
okhttpLogging: "5.0.0-alpha.2",
junit: "4.13.2"
]
libs = [
coreKtx: "androidx.core:core-ktx:${versions.coreKtx}",
retrofit: "com.squareup.retrofit2:retrofit:${versions.retrofit}",
okhttpLogging: "com.squareup.okhttp3:logging-interceptor:${versions.okhttpLogging}",
junit: "junit:junit:${versions.junit}"
]
}
|
在子模块中这样使用:
1
2
3
4
| dependencies {
implementation libs.coreKtx
implementation libs.retrofit
}
|
优势
- 集中管理版本号与依赖坐标。
- 易于迁移、上手成本低。
- 小中型项目的过渡方案。
不足
- 仍然缺乏类型安全与自动提示。
- 配置多了容易混乱。
- 修改根配置会触发子项目重新评估,影响构建速度。
- 难以管理插件或 bundle。
ext 是一种“权宜之计”:比纯手写好一点,但距离真正的现代依赖管理还差几步。
使用 buildSrc 模块 #
在根目录下创建 buildSrc 目录,Gradle 会自动编译并加载其中代码。
可以在这里定义依赖与版本常量。
buildSrc/src/main/kotlin/Dependencies.kt:
1
2
3
4
5
6
7
8
9
10
11
12
13
| object Versions {
const val coreKtx = "1.10.1"
const val retrofit = "2.9.0"
const val okhttpLogging = "5.0.0-alpha.2"
const val junit = "4.13.2"
}
object Libs {
const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}"
const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
const val okhttpLogging = "com.squareup.okhttp3:logging-interceptor:${Versions.okhttpLogging}"
const val junit = "junit:junit:${Versions.junit}"
}
|
在模块中使用:
1
2
3
4
| dependencies {
implementation(Libs.retrofit)
implementation(Libs.okhttpLogging)
}
|
优势
- 类型安全、IDE 自动补全。
- 可以定义插件、扩展函数等构建逻辑。
- 依赖集中、可复用性强。
- 适合中大型项目,特别是多团队协作。
不足
- 修改
buildSrc 会强制重新编译整个项目。 - 对构建时间有一定影响。
- 学习与维护成本更高。
- 对于仅做依赖管理来说略显“重量级”。
buildSrc 是“工程师式”的方案,强大、灵活,但稍有过度设计风险。
使用版本目录(Version Catalog) #
Gradle 7.0 起推荐使用的现代方案。
在 gradle/libs.versions.toml 中集中声明所有依赖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| [versions]
coreKtx = "1.10.1"
retrofit = "2.9.0"
okhttpLogging = "5.0.0-alpha.2"
junit = "4.13.2"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttpLogging" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
[bundles]
network = ["retrofit", "okhttp-logging-interceptor"]
|
在模块中直接使用:
1
2
3
4
5
| dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.retrofit)
implementation(libs.okhttp.logging.interceptor)
}
|
优势
- 版本与依赖完全集中。
- IDE 自动提示强、语法简洁。
- 不会触发全项目重编译。
- 支持 bundle、plugin、version alias 等现代特性。
- 官方推荐、未来趋势明确。
不足
- 迁移成本高,需要调整依赖引用方式。
- 无法直接在
buildSrc 中使用。 - 对团队约定要求较高(别名统一、文件管理规范)。
- 对于简单项目可能显得过度。
Version Catalog 已成为新标准,兼顾类型安全、性能与可维护性。
对比与建议 #
| 方式 | 学习成本 | 版本集中度 | 类型安全 | 构建性能 | 适用场景 |
|---|
| 直接写依赖 | 最低 | ★ | 无 | 优 | Demo、小项目 |
ext | 低 | ★★ | 弱 | 良 | 中小项目 |
buildSrc | 中 | ★★★ | 强 | 一般 | 中大型项目 |
| Version Catalog | 中等 | ★★★★★ | 强 | 最优 | 大型、多团队项目 |
建议:
- 新项目建议直接上 Version Catalog。
- 已有项目可从
ext 或 buildSrc 逐步迁移。 - 对于大型项目,可混合使用:Version Catalog 管理版本号,
buildSrc 管理构建逻辑。 - 无论哪种方式,都应建立“依赖声明规范”,禁止模块私自引入未注册依赖。
结语 #
依赖管理是 Android 工程化的地基之一。
当项目规模上升、团队扩大、构建频率增加,越早建立清晰、集中、可扩展的依赖管理体系,就越能避免未来的混乱。
选择哪种方式取决于项目规模与团队成熟度,但如果你打算长期维护一个 Android 应用,那就别犹豫——从 Version Catalog 开始。