Administrator
发布于 2026-08-25 / 26 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 40 篇:Android 依赖管理:Version Catalogs 与依赖治理

上一篇聊了 CI/CD 实践,这篇继续工程效率方向——依赖管理。多模块项目里,依赖版本不一致是个经典问题:模块 A 用 Retrofit 2.9,模块 B 用 2.11,编译不报错但运行时行为不一致。Version Catalogs 就是解决这个问题的。

传统依赖管理的问题

在 Version Catalogs 出现前,Android 项目管理依赖通常有三种方式:

1. 直接在 build.gradle 里写

dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.okhttp3:okhttp:4.9.3")
}

问题:每个模块各自声明,版本散落各处,升级时要逐个改。

2. 用 ext 或 buildSrc 管理版本

// buildSrc/src/main/java/Dependencies.kt
object Versions {
    const val retrofit = "2.11.0"
    const val okhttp = "4.12.0"
}

object Deps {
    const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
    const val okhttp = "com.squareup.okhttp3:okhttp:${Versions.okhttp}"
}

比直接写好,但 buildSrc 每次改动都会触发全量重编译,大型项目改一个版本号要等两分钟。

3. Extra Properties

// 根 build.gradle
extra["retrofitVersion"] = "2.11.0"

// 子模块
dependencies {
    implementation("com.squareup.retrofit2:retrofit:${rootProject.extra["retrofitVersion"]}")
}

能用但类型不安全,IDE 不提示,拼错了编译时才报。

Version Catalogs

Gradle 7.0 引入,7.4 成为稳定特性。通过一个 TOML 文件统一管理所有依赖:

# gradle/libs.versions.toml

[versions]
retrofit = "2.11.0"
okhttp = "4.12.0"
compose-bom = "2024.09.00"
kotlin = "1.9.24"

[libraries]
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }

[bundles]
network = ["retrofit", "okhttp", "okhttp-logging"]

[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

在模块中使用:

dependencies {
    // 直接引用
    implementation(libs.retrofit)
    implementation(libs.okhttp)
    
    // 使用 bundle
    implementation(libs.network)
    
    // 使用 BOM
    implementation(platform(libs.compose.bom))
}

Version Catalogs 的优势

  1. 类型安全:Gradle 生成 libs 访问器,IDE 自动补全,拼错直接报红

  2. 单文件管理:所有版本集中在 TOML 文件中

  3. 增量编译:改 TOML 不会触发 buildSrc 重编译

  4. Bundle 支持:把相关依赖打包成一组,一行引用

Bundle 的妙用

把经常一起使用的依赖组成 Bundle:

[bundles]
androidx-lifecycle = ["lifecycle-runtime", "lifecycle-viewmodel", "lifecycle-livedata"]
compose-ui = ["compose-ui", "compose-ui-graphics", "compose-ui-tooling", "compose-material3"]
dependencies {
    implementation(libs.androidx.lifecycle)
    implementation(libs.compose.ui)
}

不用一个个 implementation,简洁很多。

BOM 的使用

BOM(Bill of Materials)是另一种版本管理方式,适合库的版本联动:

[versions]
compose-bom = "2024.09.00"

[libraries]
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
compose-ui = { module = "androidx.compose.ui:ui", version = "none" }
compose-material3 = { module = "androidx.compose.material3:material3", version = "none" }
dependencies {
    implementation(platform(libs.compose.bom))
    implementation(libs.compose.ui) // 版本由 BOM 统一管理
    implementation(libs.compose.material3)
}

BOM 适合管理一个生态的依赖(如 Compose、Firebase),Version Catalogs 适合管理全局依赖。两者可以结合使用。

依赖冲突排查

# 查看依赖树
./gradlew :app:dependencies --configuration releaseRuntimeClasspath

# 查看某个依赖的来源
./gradlew :app:dependencyInsight --dependency retrofit --configuration releaseRuntimeClasspath

常见冲突场景:两个库各自依赖了不同版本的同一个传递依赖。Gradle 默认选最高版本,但 API 不兼容时会崩。

解决方式:

// 强制使用某个版本
configurations.all {
    resolutionStrategy {
        force("com.squareup.okhttp3:okhttp:4.12.0")
    }
}

// 排除某个传递依赖
implementation("com.example:lib:1.0") {
    exclude(group = "com.squareup.okhttp3")
}

依赖自动化更新

手动检查更新太低效。几个工具:

Renovate

GitHub/GitLab CI 集成,自动发 PR 升级依赖:

// renovate.json
{
  "extends": ["config:base"],
  "schedule": ["before 6am on Monday"],
  "packageRules": [
    {
      "groupName": "Kotlin",
      "matchPackagePatterns": ["^org.jetbrains.kotlin"]
    }
  ]
}

Gradle Versions Plugin

// build.gradle
plugins {
    id("com.github.ben-manes.versions") version "0.51.0"
}
./gradlew dependencyUpdates  # 检查最新版本

依赖治理建议

  1. 统一入口:所有第三方依赖走 Version Catalogs,不要在模块 build.gradle 里直接写版本号

  2. 定期升级:每月或每两周跑一次依赖检查,分批升级

  3. 大版本升级单独 PR:Retrofit 2.x → 3.x 这种大版本变化可能有 breaking change,单独 PR 测试

  4. 移除不用依赖:用 ./gradlew dependencyAnalysis 或 Knit 工具检查无用依赖

  5. 安全扫描:在 CI 中集成 Dependabot 或 OWASP Dependency Check

小结

依赖管理看似简单但直接影响项目稳定性和构建效率。Version Catalogs 是当前最佳实践,新项目应该直接用,存量项目值得花一天迁移。配合 Renovate 做自动更新,基本可以告别手动管版本的日子。

下一篇聊聊 Android 蓝牙 BLE 开发实战。


评论