Android App Development
Jetpack Compose: Migration to Gradle Kotlin DSL
March 21, 2022Let’s explain using gradle kotlin dsl with buildSrc.
In this blog, we will learn how to migrate our Android application project from a Groovy-based Gradle system to a Kotlin-based Gradle system with the help of Kotlin DSL.
Introduction
Different ways of managing Gradle dependencies:
- Manual Management
- Google’s Recommendation using “ext”
- Kotlin DSL+ buildSrc
We will apply Kotlin DSL + buildSrc step in our projects.
What is buildSrc
buildSrc
is a directory at the project root level which contains build info. We can use this directory to enable kotlin-dsl
and write logic related to custom configuration and share them across the project. It was one of the most used approaches in recent days because of its testability.
The directory
buildSrc
is treated as an included build. Upon discovery of the directory, Gradle automatically compiles and tests this code and puts it in the classpath of your build script. For multi-project builds, there can be only onebuildSrc
directory, which has to sit in the root project directory.buildSrc
should be preferred over script plugins as it is easier to maintain, refactor and test the code — Gradle Docs
as the docs say, in multi-module projects, there is only one buildSrc module and all modules can access it since it is placed in the classpath of build script, seems like a good place to put our Gradle logics to be reused.
Why buildSrc — Kotlin DSL
- Compile-Time errors checking
- Auto Completion and content assists
- Friendly code navigation
- Quick documentation (Kotlin function based)
- Consistency of using the same language across the application
- Enhanced IDE editing experience
Create buildSrc Kotlin Module
- The First Step, Create Kotlin Library module name it buildSrc.
- After selecting Finish you will get the following error.
FAILURE: Build failed with an exception.
* What went wrong:
‘buildSrc’ cannot be used as a project name as it is a reserved name
- Remove include ‘:buildSrc’ in settings.gradle.
- Convert the file name from
build.gradle
tobuild.gradle.kts
in buildSrc folder.
- After selecting Refactor, enable the option of
’kotlin-dsl’
in build.gradle.kts
buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
}repositories {
google()
mavenCentral()
gradlePluginPortal()
}
- Click on sync now to finish the set-up.
Convert the settings.gradle
- Convert the file name from
settings.gradle
tosettings.gradle.kts
. After that, if you try to compile, errors as below will show.
- You need to change
include ’:app’
toinclude(":app")
That’s it. You’re done for settings.gradle.kts
. You can compile the project and it works with other Gradle files.
Convert the root project build.gradle
- Same as the first file, convert the
build.gradle
tobuild.gradle.kts
, using the steps provided above. Now you need to fix the syntax accordingly.
Before
After
Convert the App Module’s build.gradle
Finally, the last file to convert to Kotlin, which has the most syntax change.
But before that, let’s convert the build.gradle
to build.gradle.kts
first, using the steps provided above.
Now, we can continue to convert the syntax as following.
- plugin code block
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
to the below
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
- android code block
android {
compileSdk 32
defaultConfig {
applicationId "com.developersancho.migrationgradledsl"
minSdk 23
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
to the below
android {
compileSdk = 32
defaultConfig {
applicationId = "com.developersancho.migrationgradledsl"
minSdk = 23
targetSdk = 32
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = rootProject.extra["compose_version"] as String
}
packagingOptions {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
- dependencies code block
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'androidx.activity:activity-compose:1.4.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}
to the below
dependencies {
implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.compose.ui:ui:${rootProject.extra["compose_version"]}")
implementation("androidx.compose.material:material:${rootProject.extra["compose_version"]}")
implementation("androidx.compose.ui:ui-tooling-preview:${rootProject.extra["compose_version"]}")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.1")
implementation("androidx.activity:activity-compose:1.4.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:${rootProject.extra["compose_version"]}")
debugImplementation("androidx.compose.ui:ui-tooling:${rootProject.extra["compose_version"]}")
debugImplementation("androidx.compose.ui:ui-test-manifest:${rootProject.extra["compose_version"]}")
}
Now we done. All the Gradle file is now converted to Kotlin.
Conclusion
I highly recommend the “Kotlin DSL + buildSrc” option. It may not seem like it’s that big of a deal, but managing Gradle dependencies is a pain, and having autocomplete and click support is a game changer. No more switching back and forth between files manually.
Happy and healthy coding!
Author: Mesut Genç