Version catalog enables to add and maintain dependencies and plugins at a central place.
In a multi-module project adding dependencies individually including versions in each module build.gradle
is not ideal and not a recommended approach. If you have to change a version of a dependency then you have to change in each module build.gradle
file wherever it’s added.
There are many other ways to handle dependencies in once place But Version catalog is one of the recommended ones. It makes managing dependencies easy, scalable and maintainable.
In this story we will see how to introduce Version Catalog in an android multi-module project.
Let’s get started!
Version Catalog file
Create a version catalog file in the root level gradle
folder and name it libs.versions.toml
.
In libs.versions.toml
file add the following sections.
[versions] [libraries] [plugins]
[versions]
— defines version string for dependencies and plugins, they are used in[libraries]
and[plugins]
sections.[libraries]
— defines all dependencies used in the project[plugins]
— defines plugins
Migrate Dependencies
To use dependency via Version Catalog
, we need to add the dependency in both [versions]
and [libraries]
sections of the libs.versions.toml
file.
We will take an example of hilt
dependency and migrate it, the same will be applied for all other dependencies.
Before moving Hilt
dependencies to the version catalog.
implementation("com.google.dagger:hilt-android:2.44") kapt("com.google.dagger:hilt-android-compiler:2.44")
After migrating Hilt
dependencies to the version catalog. Each dependency will be split into group
and name
as in the section below.
[versions] daggerHilt = "2.44" [libraries] dagger-hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "daggerHHilt" } dagger-hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "daggerHilt" }
Adding these dependencies in each module’s build.gradle
file where they are required.
dependencies { implementation(libs.dagger.hilt) kapt(libs.dagger.hilt.compiler) }
Job Offers
Please pay attention to the naming. e.g the defined dependencies inside libs.versions.toml
file with name dagger-hilt
is used as libs.dagger.hilt
similarly dagger-hilt-compiler
defined inside file is added as libs.dagger.hilt.compiler
inside build.gradle
. So naming conventions should be used as kebab case for better naming assistance.
Migrate BOM Dependencies
We need to define BOM dependencies in the Version Catalog slightly differently.
As in BOM only BOM dependency defines version the rest are mentioned without version, taking an automatic version per dependency based on BOM version.
Let’s take an example of Compose BOM.
Before moving Compose BOM dependencies into the version catalog.
// jetpack compose bom implementation(platform("androidx.compose:compose-bom:2023.05.01")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material3:material3")
After moving Compose BOM dependencies inside the version catalog.
[versions] composeBom = "2023.05.01" [libraries] compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } compose-ui = { module = "androidx.compose.ui:ui" } compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } compose-material3 = { module = "androidx.compose.material3:material3" }
Compose BOM dependency is defined in a similar way as a normal dependency. But each Compose dependency which does not require a version against has to be defined as module
.
Using these dependencies inside the module build.gradle
file.
// jetpack compose bom implementation(platform(libs.compose.bom) implementation(libs.compose.ui) implementation(libs.compose.ui.graphics) implementation(libs.compose.ui.tooling.preview) implementation(libs.compose.maerial3)
Migrate Plugins
Migrating plugins is also similar where we will add entries in [versions]
and [plugins]
sections of the libs.versions.toml
file and use them in the plugins{}
block with their catalog names.
Usage of plugins before moving to the version catalog.
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id "com.android.application" version "8.1.3" apply false id "com.android.library" version "8.1.3" apply false id "org.jetbrains.kotlin.android" version "1.8.10" apply false } // app level configurations plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } // module level configurations plugins { id("com.android.library") id("org.jetbrains.kotlin.android") id("kotlin-kapt") }
Moving these plugins into the version catalog as mentioned below.
[versions] kotlin = "1.8.10" androidGradlePlugin = "8.1.3" [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
As above adding versions into the [versions]
sections and adding plugins into [plugins]
section referencing the versions added in [versions]
section.
Using plugins from version catalog
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false } // app level plugins plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) } // module level plugins plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android) id("kotlin-kapt") }
Use alias
for plugins which are being used from the version catalog and use id
for other plugins which are still not defined in version catalog.
Sync and run your project whenever you add dependencies and plugins from the version catalog.
As mentioned earlier plugins and
dependencies naming should be used as kebab-case for better naming assistance.
Thats it for now, I hope it was helpful.
Remember to follow and 👏 if you liked it 🙂
— — — — — — — — — — —
This article was previously published on proandroiddev.com