Skip to Content

Version Catalog

Version Catalog là cách quản lý versions của dependencies và plugins tập trung trong một file duy nhất. Thay vì khai báo version scattered khắp các build files, bạn định nghĩa tất cả trong libs.versions.toml.

Tại sao cần Version Catalog?

Vấn đề với cách cũ

// ❌ Cách cũ: Version hardcode trong build.gradle.kts dependencies { implementation("androidx.core:core-ktx:1.15.0") implementation("androidx.compose.ui:ui:1.7.5") implementation("com.squareup.retrofit2:retrofit:2.9.0") }

Nhược điểm:

  • Khó maintain khi có nhiều modules
  • Dễ conflict versions giữa các modules
  • Không có IDE auto-complete
  • Khó tìm để cập nhật

Giải pháp: Version Catalog

// ✅ Version Catalog: Type-safe references dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.ui) implementation(libs.retrofit) }

Ưu điểm:

  • ✅ Quản lý versions tập trung
  • ✅ IDE auto-complete và navigation
  • ✅ Type-safe (báo lỗi compile-time)
  • ✅ Dễ dàng cập nhật versions
  • ✅ Tái sử dụng across modules

Cấu trúc file libs.versions.toml

File Version Catalog đặt tại gradle/libs.versions.toml và có 3 sections chính:

[versions] # Định nghĩa version numbers [libraries] # Định nghĩa dependencies [plugins] # Định nghĩa Gradle plugins [bundles] # (Optional) Nhóm các libraries

Section [versions]

Định nghĩa biến chứa version numbers:

[versions] kotlin = "2.0.21" agp = "8.7.2" compose-bom = "2024.11.00" core-ktx = "1.15.0" lifecycle = "2.8.7" activity-compose = "1.9.3" navigation = "2.8.4" room = "2.6.1" retrofit = "2.11.0" hilt = "2.52" ksp = "2.0.21-1.0.27" junit = "4.13.2"

💡 Mẹo: Naming convention: Sử dụng kebab-case (dấu gạch ngang) cho tên biến. Ví dụ: compose-bom, core-ktx.


Section [libraries]

Định nghĩa dependencies với group, name, và version.ref:

[libraries] # Cách 1: Full format androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } # Cách 2: Compact format (module notation) retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } # Cách 3: Version inline (không khuyến khích) junit = { module = "junit:junit", version = "4.13.2" } # Libraries không có version (dùng với BOM) androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" }

Sử dụng trong build.gradle.kts

dependencies { // libs.{library-alias} - dấu gạch ngang thành dấu chấm implementation(libs.androidx.core.ktx) implementation(libs.retrofit) testImplementation(libs.junit) }

📝 Lưu ý: Alias androidx-core-ktx trong TOML trở thành libs.androidx.core.ktx trong Kotlin DSL (dấu - thành .)


Section [plugins]

Định nghĩa Gradle plugins:

[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-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" }

Sử dụng trong build files

// build.gradle.kts (Project-level) plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false } // build.gradle.kts (Module-level) plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.hilt) }

Section [bundles] (Optional)

Nhóm nhiều libraries thường đi cùng nhau:

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

Sử dụng bundle

dependencies { implementation(libs.bundles.compose) implementation(libs.bundles.retrofit) }

Bill of Materials (BOM)

BOM là một dependency đặc biệt quản lý versions của một họ libraries. Khi sử dụng BOM, bạn không cần khai báo version cho từng library trong họ đó.

Khai báo BOM

[versions] compose-bom = "2024.11.00" [libraries] # BOM androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } # Libraries trong BOM - KHÔNG cần version androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" }

Sử dụng BOM

dependencies { // Import BOM - quyết định versions implementation(platform(libs.androidx.compose.bom)) // Các libraries không cần version implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.material3) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling.preview) }

⚠️ Quan trọng: Khi dùng BOM, KHÔNG khai báo version cho các libraries thuộc BOM đó. BOM sẽ tự động cung cấp compatible versions.


Ví dụ hoàn chỉnh

libs.versions.toml

[versions] # Core kotlin = "2.0.21" agp = "8.7.2" ksp = "2.0.21-1.0.27" # AndroidX core-ktx = "1.15.0" lifecycle = "2.8.7" activity-compose = "1.9.3" navigation = "2.8.4" # Compose compose-bom = "2024.11.00" # Database room = "2.6.1" datastore = "1.1.1" # Network retrofit = "2.11.0" okhttp = "4.12.0" kotlinx-serialization = "1.7.3" # DI hilt = "2.52" hilt-navigation-compose = "1.2.0" # Image coil = "2.7.0" # Testing junit = "4.13.2" androidx-junit = "1.2.1" espresso = "3.6.1" [libraries] # Core androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } # Compose BOM androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } # Navigation androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } # Room room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } # DataStore datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" } # Network retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } # 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" } hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-navigation-compose" } # Image coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } # Testing junit = { module = "junit:junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-junit" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" } [bundles] compose = ["androidx-ui", "androidx-ui-graphics", "androidx-ui-tooling-preview", "androidx-material3"] compose-debug = ["androidx-ui-tooling"] lifecycle = ["androidx-lifecycle-runtime-ktx", "androidx-lifecycle-viewmodel-compose"] room = ["room-runtime", "room-ktx"] retrofit = ["retrofit", "retrofit-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" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" }

Migration từ String Dependencies

Nếu project hiện tại đang dùng string dependencies, migrate theo các bước:

Bước 1: Tạo file libs.versions.toml

# Tạo file trong thư mục gradle/ touch gradle/libs.versions.toml

Bước 2: Migrate từng dependency

Trước:

dependencies { implementation("androidx.core:core-ktx:1.15.0") }

Sau - Trong libs.versions.toml:

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

Sau - Trong build.gradle.kts:

dependencies { implementation(libs.androidx.core.ktx) }

Bước 3: Migrate plugins

Trước:

plugins { id("com.android.application") version "8.7.2" apply false }

Sau:

# libs.versions.toml [versions] agp = "8.7.2" [plugins] android-application = { id = "com.android.application", version.ref = "agp" }
// build.gradle.kts plugins { alias(libs.plugins.android.application) apply false }

💡 Mẹo: Migrate dần dần, một dependency/plugin mỗi lần. Build có thể consume cả hai cách đồng thời.


Best Practices

1. Naming Convention

# ✅ Tốt: kebab-case androidx-core-ktx = { ... } compose-bom = "2024.11.00" # ❌ Tránh: camelCase hoặc snake_case androidxCoreKtx = { ... } compose_bom = "2024.11.00"

2. Grouped Versions

[versions] # Group related libraries kotlin = "2.0.21" ksp = "2.0.21-1.0.27" # KSP tied to Kotlin version compose-bom = "2024.11.00" room = "2.6.1"

3. Comment Sections

[libraries] # Core AndroidX androidx-core-ktx = { ... } androidx-activity-compose = { ... } # Compose UI androidx-compose-bom = { ... } androidx-ui = { ... } # Database room-runtime = { ... }

📚 Tham khảo

Last updated on