Skip to content

版本目录

源:Gradle 官方文档 - Version Catalogs | Android 官方文档 - 迁移到版本目录

Version Catalog 是 Gradle 7.0+ 引入的依赖管理方案,通过集中式配置文件管理所有依赖版本,提供类型安全的依赖声明。

Version Catalog 简介

传统依赖管理的问题

分散的版本定义

kotlin
// app/build.gradle.kts
dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
}

// feature/build.gradle.kts
dependencies {
    implementation("androidx.core:core-ktx:1.10.0")  // 版本不一致!
}

问题

  • 版本号分散在各个模块
  • 容易出现版本不一致
  • 升级困难且易出错
  • 没有类型安全检查

Version Catalog 的优势

集中管理

  • 单一文件定义所有版本
  • 跨模块版本一致性
  • 便于统一升级

类型安全

  • IDE 自动补全
  • 编译期错误检查
  • 重构支持

依赖组

  • 将相关库打包为 bundle
  • 简化常用组合

创建 Version Catalog

文件位置

标准位置gradle/libs.versions.toml

自动识别:Gradle 7.4+ 自动识别并应用此文件

TOML 文件结构

toml
[versions]
# 版本号定义

[libraries]
# 库定义

[bundles]
# 依赖组定义

[plugins]
# 插件定义

versions 版本号定义

基本定义

toml
[versions]
kotlin = "2.1.0"
compose = "1.7.5"
androidx-core = "1.15.0"
retrofit = "2.11.0"

命名规范

  • 使用小写字母
  • 单词间使用连字符 -
  • 语义清晰

版本号引用

toml
[versions]
kotlin = "2.1.0"

[libraries]
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }

libraries 库定义

完整语法

toml
[libraries]
androidx-core = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core" }

简化语法

toml
[libraries]
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }

最简语法(版本直接写入):

toml
[libraries]
junit = "junit:junit:4.13.2"

复杂示例

toml
[versions]
compose = "1.7.5"
compose-compiler = "1.5.8"

[libraries]
# Compose UI
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "compose" }
compose-material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" }

# Compose Foundation
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" }
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }

不指定版本

toml
[libraries]
# 使用 BOM 管理版本
compose-bom = "androidx.compose:compose-bom:2024.02.00"
compose-ui = { module = "androidx.compose.ui:ui" }
compose-material3 = { module = "androidx.compose.material3:material3" }

bundles 依赖组

基本用法

toml
[versions]
retrofit = "2.11.0"

[libraries]
retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
retrofit-converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }

[bundles]
retrofit = ["retrofit-core", "retrofit-converter-gson", "retrofit-converter-moshi"]

使用

kotlin
dependencies {
    implementation(libs.bundles.retrofit)
    // 等同于
    // implementation(libs.retrofit.core)
    // implementation(libs.retrofit.converter.gson)
    // implementation(libs.retrofit.converter.moshi)
}

常用 bundle 示例

toml
[versions]
compose = "1.7.5"
lifecycle = "2.7.0"

[libraries]
# Compose
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "compose" }
compose-activity = "androidx.activity:activity-compose:1.9.3"

# Lifecycle
lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }

[bundles]
compose = ["compose-ui", "compose-ui-tooling-preview", "compose-material3", "compose-activity"]
lifecycle = ["lifecycle-runtime", "lifecycle-viewmodel", "lifecycle-viewmodel-compose"]

plugins 插件定义

基本语法

toml
[versions]
agp = "8.7.3"
kotlin = "2.1.0"

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

使用

kotlin
// build.gradle.kts (project)
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.android) apply false
}
kotlin
// app/build.gradle.kts
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

在项目中使用

自动生成的访问器

库访问器规则

toml
[libraries]
androidx-core-ktx = "androidx.core:core-ktx:1.15.0"

转换为

kotlin
libs.androidx.core.ktx

转换规则

  • - 转为 .
  • 驼峰命名

使用库

kotlin
// build.gradle.kts
dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    
    // Bundle
    implementation(libs.bundles.compose)
    
    // 测试
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.test.espresso.core)
}

使用插件

kotlin
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
}

完整配置示例

libs.versions.toml

toml
[versions]
# SDK
compileSdk = "35"
minSdk = "24"
targetSdk = "35"

# Plugins
agp = "8.7.3"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"

# AndroidX
androidx-core = "1.15.0"
androidx-appcompat = "1.7.0"
androidx-activity = "1.9.3"
androidx-lifecycle = "2.7.0"

# Compose
compose-bom = "2024.12.01"
compose-compiler = "1.5.8"

# Network
retrofit = "2.11.0"
okhttp = "4.12.0"

# DI
hilt = "2.52"

# Testing
junit = "4.13.2"
androidx-test-ext = "1.2.1"
espresso = "3.6.1"

[libraries]
# AndroidX Core
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity" }

# Lifecycle
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }

# Compose
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
compose-ui = { group = "androidx.compose.ui", name = "ui" }
compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
compose-material3 = { group = "androidx.compose.material3", name = "material3" }
compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }

# Network
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }

# DI
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }

# Testing
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" }
androidx-test-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }

[bundles]
compose = ["compose-ui", "compose-ui-graphics", "compose-ui-tooling-preview", "compose-material3"]
lifecycle = ["androidx-lifecycle-runtime-ktx", "androidx-lifecycle-viewmodel-ktx", "androidx-lifecycle-viewmodel-compose"]
retrofit = ["retrofit-core", "retrofit-converter-gson", "okhttp-logging"]

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }

build.gradle.kts (project)

kotlin
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.android.library) apply false
    alias(libs.plugins.kotlin.android) apply false
    alias(libs.plugins.kotlin.compose) apply false
    alias(libs.plugins.ksp) apply false
    alias(libs.plugins.hilt) apply false
}

build.gradle.kts (app)

kotlin
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
    alias(libs.plugins.ksp)
    alias(libs.plugins.hilt)
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation(libs.androidx.activity.compose)
    
    // Compose BOM
    implementation(platform(libs.compose.bom))
    implementation(libs.bundles.compose)
    
    // Lifecycle
    implementation(libs.bundles.lifecycle)
    
    // Network
    implementation(libs.bundles.retrofit)
    
    // DI
    implementation(libs.hilt.android)
    ksp(libs.hilt.compiler)
    
    // Testing
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.test.ext.junit)
    androidTestImplementation(libs.androidx.test.espresso.core)
    androidTestImplementation(platform(libs.compose.bom))
    androidTestImplementation(libs.compose.ui.test.junit4)
    
    // Debug
    debugImplementation(libs.compose.ui.tooling)
    debugImplementation(libs.compose.ui.test.manifest)
}

迁移到 Version Catalog

从传统方式迁移

迁移前

kotlin
// buildSrc/src/main/kotlin/Versions.kt
object Versions {
    const val kotlin = "2.1.0"
    const val compose = "1.7.5"
}

object Deps {
    const val composeUi = "androidx.compose.ui:ui:${Versions.compose}"
}

// build.gradle.kts
dependencies {
    implementation(Deps.composeUi)
}

迁移后

toml
# gradle/libs.versions.toml
[versions]
kotlin = "2.1.0"
compose = "1.7.5"

[libraries]
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
kotlin
// build.gradle.kts
dependencies {
    implementation(libs.compose.ui)
}

自动迁移工具

Android Studio 提供迁移助手:

ToolsVersion Catalog Migration


最佳实践

命名规范

  • 使用连字符分隔
  • 语义清晰
  • 保持一致性

版本号管理

  • 集中定义常用版本
  • 相关库使用同一版本
  • 定期更新

使用 bundles

  • 将常用组合定义为 bundle
  • 简化依赖声明
  • 便于统一管理

插件管理

  • 在 catalog 中定义插件版本
  • 使用 alias 引用
  • 避免硬编码版本

团队协作

  • 提交 libs.versions.toml 到版本控制
  • 统一团队版本
  • Code Review 时检查版本一致性