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?
Phần tiêu đề “Tại sao cần Version Catalog?”Vấn đề với cách cũ
Phần tiêu đề “Vấn đề với cách cũ”// ❌ Cách cũ: Version hardcode trong build.gradle.ktsdependencies { 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
Phần tiêu đề “Giải pháp: Version Catalog”// ✅ Version Catalog: Type-safe referencesdependencies { 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
Phần tiêu đề “Cấu trúc file libs.versions.toml”File Version Catalog đặt tại gradle/libs.versions.toml và có 3 sections chính:
flowchart TB subgraph TOML["libs.versions.toml"] V["[versions]<br/>kotlin = 2.0.21<br/>agp = 8.7.2"] L["[libraries]<br/>androidx-core-ktx<br/>retrofit"] P["[plugins]<br/>android-application<br/>kotlin-android"] B["[bundles]<br/>compose<br/>retrofit"] end
V --> L V --> P L --> B
L --> BG["build.gradle.kts<br/>libs.androidx.core.ktx"] P --> BG2["build.gradle.kts<br/>libs.plugins.android.application"]
style V fill:#e3f2fd style L fill:#e8f5e9 style P fill:#fff3e0 style B fill:#fce4ec[versions]# Định nghĩa version numbers
[libraries]# Định nghĩa dependencies
[plugins]# Định nghĩa Gradle plugins
[bundles]# (Optional) Nhóm các librariesSection [versions]
Phần tiêu đề “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]
Phần tiêu đề “Section [libraries]”Định nghĩa dependencies với group, name, và version.ref:
[libraries]# Cách 1: Full formatandroidx-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
Phần tiêu đề “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-ktxtrong TOML trở thànhlibs.androidx.core.ktxtrong Kotlin DSL (dấu-thành.)
Section [plugins]
Phần tiêu đề “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
Phần tiêu đề “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)
Phần tiêu đề “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
Phần tiêu đề “Sử dụng bundle”dependencies { implementation(libs.bundles.compose) implementation(libs.bundles.retrofit)}Bill of Materials (BOM)
Phần tiêu đề “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
Phần tiêu đề “Khai báo BOM”[versions]compose-bom = "2024.11.00"
[libraries]# BOMandroidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
# Libraries trong BOM - KHÔNG cần versionandroidx-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
Phần tiêu đề “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
Phần tiêu đề “Ví dụ hoàn chỉnh”libs.versions.toml
Phần tiêu đề “libs.versions.toml”[versions]# Corekotlin = "2.0.21"agp = "8.7.2"ksp = "2.0.21-1.0.27"
# AndroidXcore-ktx = "1.15.0"lifecycle = "2.8.7"activity-compose = "1.9.3"navigation = "2.8.4"
# Composecompose-bom = "2024.11.00"
# Databaseroom = "2.6.1"datastore = "1.1.1"
# Networkretrofit = "2.11.0"okhttp = "4.12.0"kotlinx-serialization = "1.7.3"
# DIhilt = "2.52"hilt-navigation-compose = "1.2.0"
# Imagecoil = "2.7.0"
# Testingjunit = "4.13.2"androidx-junit = "1.2.1"espresso = "3.6.1"
[libraries]# Coreandroidx-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 BOMandroidx-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" }
# Navigationandroidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
# Roomroom-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" }
# DataStoredatastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
# Networkretrofit = { 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" }
# DIhilt-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" }
# Imagecoil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
# Testingjunit = { 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
Phần tiêu đề “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
Phần tiêu đề “Bước 1: Tạo file libs.versions.toml”# Tạo file trong thư mục gradle/touch gradle/libs.versions.tomlBước 2: Migrate từng dependency
Phần tiêu đề “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
Phần tiêu đề “Bước 3: Migrate plugins”Trước:
plugins { id("com.android.application") version "8.7.2" apply false}Sau:
[versions]agp = "8.7.2"
[plugins]android-application = { id = "com.android.application", version.ref = "agp" }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
Phần tiêu đề “Best Practices”1. Naming Convention
Phần tiêu đề “1. Naming Convention”# ✅ Tốt: kebab-caseandroidx-core-ktx = { ... }compose-bom = "2024.11.00"
# ❌ Tránh: camelCase hoặc snake_caseandroidxCoreKtx = { ... }compose_bom = "2024.11.00"2. Grouped Versions
Phần tiêu đề “2. Grouped Versions”[versions]# Group related librarieskotlin = "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
Phần tiêu đề “3. Comment Sections”[libraries]# Core AndroidXandroidx-core-ktx = { ... }androidx-activity-compose = { ... }
# Compose UIandroidx-compose-bom = { ... }androidx-ui = { ... }
# Databaseroom-runtime = { ... }