Switch from Gradle Groovy to Kotlin DSL: Android
The new way to manage dependencies in android using Kotlin DSL.
Pros:
1. Kotlin First
2. Making hard un-understandable groovy syntax file to easy kotlin syntax file.
3. Helps in managing dependency and their versions easily in multi-module project.
Cons:
1. Slow build time as compared to groovy
Let’s get started:
- On the root project, add a new package
buildSrc
- Next add a new file with in the build.src package — name
build.gradle.kts
and add the followingkotlin-dsl
plugin.
import org.gradle.kotlin.dsl.`kotlin-dsl`
plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}
Now click on Sync now and let the project build successfully.
Next steps now,
1. Create a package hierarchy with src/main/java
2. Now create a file that will have the versions and dependencies. — I am naming it as Deps.kt
.The structure would look like
3. Rename settings.gradle
to settings.gradle.kts
include ‘:app’
This will be changed to
include (":app")
//If there are more than one module, keep them comma seperated
4. Rename build.gradle
(project-level) to build.gradle.kts
and refactor the file like below build.gradle.kts
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath ("com.android.tools.build:gradle:${Versions.GradleVersion}")
classpath ("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KotlinVersion}")
classpath ("com.google.gms:google-services:4.3.8")
classpath ("com.google.firebase:perf-plugin:1.4.0")
classpath ("com.google.firebase:firebase-crashlytics-gradle:2.6.1")
classpath ("com.google.dagger:hilt-android-gradle-plugin:${Versions.HiltVersion}")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven ("https://maven.google.com")
maven ("https://jitpack.io")
flatDir {
dirs ("libs")
}
}
}
tasks.register("clean", Delete::class) {
delete (rootProject.buildDir)
}//If you have multiple task follow the same way like clean tasks is done. You can give a read at https://docs.gradle.org/current/userguide/migrating_from_groovy_to_kotlin_dsl.html
Here you see the Versions are coming from Deps file which we created under buildSrc
. So the Deps file looks like —
object Versions {
const val KotlinVersion = "1.4.32"
const val HiltVersion = "2.35.1"
const val GradleVersion = "4.1.3"
}
5. Now comes the longest file to refactor — the app level build.gradle
. Change the build.gradle(app)level
file to build.gradle.kts
- Refactor the plugins block as
plugins {
id("com.android.application")
id("com.google.firebase.crashlytics")
id("com.google.firebase.firebase-perf")
kotlin("android")
kotlin("kapt")
id("dagger.hilt.android.plugin")
}
Define an object AppConfig
in the Deps.kt file, add/remove the ones which are fitting to your requirements
object AppConfig {
const val TestInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
const val CompileSdkVersion = 30
const val MinSdkVersion = 21
const val TargetSdkVersion = 30
const val VersionCode = 1
const val VersionName = "1.1.0"
}
- Now under the
android
block perform the refactoring like below
android {
compileSdkVersion(AppConfig.CompileSdkVersion)
defaultConfig {
multiDexEnabled = true
applicationId = "com.codedsun"
minSdkVersion (AppConfig.MinSdkVersion)
targetSdkVersion(AppConfig.TargetSdkVersion)
versionCode = AppConfig.VersionCode
versionName = AppConfig.VersionName
testInstrumentationRunner = AppConfig.TestInstrumentationRunner
vectorDrawables.useSupportLibrary = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding = true
}
//...File contains more lines
}
→ Now if you have multiple buildtypes, define it as below inside the android
block. You have to use getByName
(“release”) or (“debug”)
getByName("release") {
minifyEnabled(true)
isShrinkResources = true
zipAlignEnabled(true)
android.defaultConfig.vectorDrawables.useSupportLibrary = true
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
Important Part: Not easily available on the internet
Jokes apart, let’s dive in below
If you use buildConfig fields inside the build types, you can define it as below
buildConfigField ("String", "BuildName", "app-release")
The challenge is — if the buildConfig fields are defined under gradle.properties
file.
under buildTypes define :
buildTypes {
val BuildName: String by project //the property defined in gradle.properties getByName("release") {
buildConfigField ("String", "BuildName", BuildName)
...
buildConfigField("Boolean/String/Long", "BuildConfigField", "BuildConfigValue"
}
Make sure the variable BuildName (as it’s) exists in gradle.properties file
One thing to learn from here is that buildConfigField
function — takes 3 params :
type: String — The data type of the field you want to assign to the build config field. Here you can define your values as Boolean, Long, Int..etc
name: String — the name of the buildConfig field
value: String — the value of the buildConfig field which has to be in the string only, it doesn’t have to be defined as the same that you defined in the type. Example bold-marked above
- Now comes the dependencies block
implementation fileTree(dir: “libs”, include: [“*.jar”])
will be changed to
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")
If you have aar’s file also in the project, you don't have to write separately for every file
implementation('libs-1.3.0',ext:'aar') //This is wrong
Instead, include the .aar in the line which has .jar files implementation
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
- Now inside the Deps.kt file, make an object Deps and define the versions in the Versions object
object Versions {
const val KotlinVersion = "1.4.32"
const val HiltVersion = "2.35.1"
const val GradleVersion = "4.1.3"
const val CoroutinesVersion = "1.4.3"
const val AppCompat = "1.3.0"
const val ConstraintLayout = "2.0.4"
const val Material = "1.1.0-beta01"
const val Browser = "1.3.0"
const val RecyclerView = "1.2.1"
const val LifecycleExtensions = "2.2.0"
const val ViewModel = "2.3.1"
}object Deps {
const val KotlinSdkLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.KotlinVersion}"
const val AppCompat = "androidx.appcompat:appcompat:${Versions.AppCompat}"
const val ConstraintLayout = "androidx.constraintlayout:constraintlayout:${Versions.ConstraintLayout}"
const val Material = "com.google.android.material:material:${Versions.Material}"
const val Browser = "androidx.browser:browser:${Versions.Browser}"
const val RecyclerView = "androidx.recyclerview:recyclerview:${Versions.RecyclerView}"
const val LifecycleExtensions = "androidx.lifecycle:lifecycle-extensions:${Versions.LifecycleExtensions}"
const val ViewModel = "androidx.lifecycle:lifecycle-viewmodel:${Versions.ViewModel}"
Hence the dependencies block would look like
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
implementation(Deps.KotlinSdkLib)
implementation(Deps.AppCompat)
implementation(Deps.ConstraintLayout)
implementation(Deps.Material)
implementation(Deps.Browser)
implementation(Deps.RecyclerView)
implementation(Deps.LifecycleExtensions)
implementation(Deps.ViewModel)}
If you have more dependencies, follow the same process to define the dependencies and you are good to go.
Thanks for hanging in for so-long 😎. Do share your 👏 or comments below.
We are all about building products that resolve world-class problems, so if you are looking to challenge yourself, join our team at Oye! Rickshaw. We are hiring. Check for open positions.