Vincent Tsen
Vincent Tsen - AndroidDev Blog

Follow

Vincent Tsen - AndroidDev Blog

Follow

How to add Version Catalog to your Android App?

Step-by-step guide to implement Version Catalog (a dependency management tool developed by Gradle team) into your Android app

Vincent Tsen's photo
Vincent Tsen
ยทDec 16, 2022ยท

3 min read

How to add Version Catalog to your Android App?

Table of contents

  • 1. Upgrade Gradle Version
  • 2. Create libs.versions.toml
  • 3. Update the plugins block
  • 4. Update kotlinCompilerExtensionVersion
  • 5. Update library dependencies
  • Current Issue
  • Source Code

Version Catalog is a dependency management tool developed by the Gradle team. The benefit of using it is you don't need to hard code the version in multiple places, especially if you have a multi-modules project.

This article provides a step-by-step guide to integrating Version Catalog into your Android app using Android Studio. The example is based on this clean empty Jetpack Compose app template.

1. Upgrade Gradle Version

The minimum Gradle version requirement to run Version Catalog is 7.4. However, version 7.4.2 contains the latest fixes.

In the terminal, check your Gradle version.

./gradlew -version

If it is less than 7.4.2, upgrade it.

./gradlew wrapper --gradle-version 7.4.2

After running the above command, the .\wrapper\gradle-wrapper.jar, .\wrapper\gradle-wrapper.properties and .\build.gradle.kts are updated.

If you're curious about *.kts, it is a Gradle Kotlin Script. For more information, you can refer to this blog post.

2. Create libs.versions.toml

Create this .\gradle\libs.versions.toml file. Please make sure you name it correctly. I named it wrongly at first, and it took me a while to figure that out.

An example of libs.versions.toml looks like this.

[versions]
androidGradlePlugin = "7.3.0"
androidxCore = "1.8.0"
androidxComposeCompiler = "1.2.0"

[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }

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

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

[bundles]
androidx-lifeycle = ["androidx-lifecycle-runtime-ktx", "androidx-lifecycle-viewmodel-compose"]
  • [versions] - declare versions that are referenced by [plugins] and [libraries]

  • [plugins] - define a set of plugins with version

  • [libraries] - define a set of library dependencies with version

  • [bundles] - combine multiple libraries into a single reference

[bundles] works only with libraries. It won't work for plugins. For example, the following won't work.

[bundles]
android-gradle-plugin = ["android-application", "android-library"]

3. Update the plugins block

build.gradle.kts (root / project level)

Replace

plugins {
    id("com.android.application") version "7.2.2" apply false 
    id("com.android.library") version "7.2.2" apply false 
    id("org.jetbrains.kotlin.android") version "1.7.0" apply false
}

with

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

app\build.gradle.kts (app / module level)

Replace

plugins {
    id ("com.android.application")
    id ("org.jetbrains.kotlin.android")
}

with

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

It compiles and runs fine, but you can still see the following errors.

val Project.libs: LibrariesForLibs' can't be called in this context by implicit receiver. Use the explicit one if necessary

It looks like a known bug here. To get rid of this error, you can add @Suppress("DSL_SCOPE_VIOLATION")

[Updated - Jan 2, 2023]: If you get the "Expecting an expression" build error, you want to add this println("") at the end of the file as a workaround.

@Suppress("DSL_SCOPE_VIOLATION")
plugins {
    /*...*/
}

//Workaround for "Expecting an expression" build error
println("")

4. Update kotlinCompilerExtensionVersion

Instead of hard coding kotlinCompilerExtensionVersion

composeOptions { 
    kotlinCompilerExtensionVersion = "1.2.0" 
}

use libs.vesions.compose which you defined androidxComposeCompiler in the [versions] section in libs.versions.toml file

composeOptions {
    kotlinCompilerExtensionVersion = libs.versions.androidxComposeCompiler.get()
}

5. Update library dependencies

Example 1 - Single library

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

is replaced with

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

Example 2 - Multiple libraries

dependencies { 
    val lifeCycleVersion = "2.5.1" 
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifeCycleVersion") 
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifeCycleVersion") 
}

are replaced with

dependencies { 
    implementation(libs.bundles.androidx.lifeycle) 
}

Current Issue

The major issue with Version Catalog in my opinion is it won't prompt you the message when there is a new version of the library. For example:

A newer version of androidx.core:core-ktx than 1.8.0 is available: 1.9.0

There is a third-party library here, but I think it still requires you to manually run the Gradle command.

Source Code

GitHub Repository: Demo_CleanEmptyCompose(master_vercatalog branch)

Convert to Version Catalog: diff

Did you find this article valuable?

Support Vincent Tsen by becoming a sponsor. Any amount is appreciated!

See recent sponsors |ย Learn more about Hashnode Sponsors
ย 
Share this