In large multi-module Android (or any gradle-based) projects, version management starts to become a bit of a pain.
The most common way people deal with this problem is to use buildSrc, but the problem with this is that buildSrc changes cause cache invalidation throughout the build process and increase build times.
Apparently the call to action is now moved from buildSrc to includeBuild
If you have other custom build logic and build plugins, then it certainly makes sense to move to the mechanism includeBuild, but if your buildSrc only needs versioning of dependencies, there is a better way - the gradle version directory
Add version and library to settings.gradle(.kts)
Note: all my examples are in kts because the build scripts in kotlin have better DX (autocomplete, linting, etc.)
For example, this is what I added to settings.gradle.kts (expanded on the line afterwards)
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
version("androidx.navigation", "2.4.1")
version("android.material", "1.7.0-alpha01")
version("moshi", "1.13.0")
version("retrofit", "2.9.0")
version("moshi", "1.13.0")
library("android.material", "com.google.android.material", "material").versionRef("android.material")
library("androidx.navigation.fragment", "androidx.navigation", "navigation-fragment-ktx").versionRef("androidx.navigation")
library("androidx.navigation.ui", "androidx.navigation", "navigation-ui-ktx").versionRef("androidx.navigation")
library("androidx.core", "androidx.core:core-ktx:1.7.0")
library("androidx.appcompat", "androidx.appcompat:appcompat:1.4.1")
library("okhttp", "com.squareup.okhttp3:okhttp:5.0.0-alpha.6")
library("retrofit", "com.squareup.retrofit2", "retrofit").versionRef("retrofit")
library("retrofit.converter.moshi", "com.squareup.retrofit2", "converter-moshi").versionRef("retrofit")
library("moshi", "com.squareup.moshi", "moshi-kotlin").versionRef("moshi")
library("moshi.compiler", "com.squareup.moshi", "moshi-kotlin-codegen").versionRef("moshi")
bundle("androidx.appcompat", listOf("androidx.core", "androidx.appcompat"))
bundle("androidx.navigation", listOf("androidx.navigation.fragment", "androidx.navigation.ui"))
bundle("retrofit", listOf("retrofit", "retrofit.converter.moshi"))
}
}
}
- Create a "library" block
dependencyResolutionManagement {
versionCatalogs {
create("libs") {...}
}
}
2. Add version constants
version("android.material", "1.7.0-alpha01")
version("moshi", "1.13.0")
version("retrofit", "2.9.0")
3. Add each dependency
You can reference the version constant versionRef()
library("android.material", "com.google.android.material", "material").versionRef("android.material")
- If there is a set of libraries used together, create a "bundle"
bundle("androidx.appcompat", listOf("androidx.core", "androidx.appcompat"))
build.gradle(.kts) uses the version catalog in the file
The method to use these in the module's build.gradle is as follows
dependencies {
implementation(libs.bundles.androidx.appcompat)
implementation(libs.android.material)
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
implementation(libs.bundles.androidx.navigation)
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
Ordinary libraries are used like this
implementation(libs.android.material)
Although it is possible to add the entire bundle like this
implementation(libs.android.material)
What doesn’t work?
There are some things to note
Gradle 7.4+
If you are using Gradle 7.3 or lower, the release directory is an unstable/experimental API and you need to mark it as such. Starting in 7.4, they are enabled by default
Android Studio support for version management
Dependencies in the version directory will not show up in Android Studio's project structure options, and Studio will not remind you to update outdated dependencies.
As you can see below there is a warning about the version directory and the version directory dependencies are not showing up
Autocomplete only works in Kotlin
If you use build.gradle(groovy) instead of build.gradle.kts(kotlinscript) there will be no autocompletion or type checking for the libs.x.y dependency
Below is an autocomplete function that only works inside .kts files.