Migrating Gradle Build Scripts to
Kotlin DSL

Migrating Gradle Build Scripts to
Kotlin DSL

Birju Vachhani
Feb 24, 2019 · 7 min read

Originally published at:

Howdy people! It’s been a while since Gradle released support for Kotlin scripts. We have been writing Gradle script in a language called Groovy since ages. Let’s be honest, We all know that Groovy sucks! Half of the times I have been like this when there’s an issue:

Why does Groovy suck?

  • No Auto-Completion🙄
  • No Content Assist😞
  • No Navigation to Source😕
  • Don’t know what to write and how to write😪
  • I don’t like it😠

Kotlin Script to The Rescue

Gradle released support for Kotlin scripts and Kotlin DSL(In short, DSL makes the code more readable, it’s built in Kotlin feature). Finally, I don’t have to learn that lame Groovy for Gradle scripts. Now I can write my build scripts in my favorite language Kotlin. When it released, I was like:

I never learned Groovy but now, all I have to do is to be yourself and write Kotlin scripts like a PRO. How cool is that! A single language to manage your whole project. Kotlin script overcomes almost all the cons of Groovy.

Why Kotlin scripts are awesome:

  • Auto-Completion😎
  • Content Assist😍
  • Navigation to Source😱
  • Kotlin Extensions support😘
  • Errors at compile time instead of runtime💪
  • I love it❤️

Writing build scripts in Kotlin is like riding a bike🏍 (Except the bike is on fire🔥).

Sometimes it can be a bit messy to rewrite gradle.build into gradle.build.kts files, especially when all its cache is malfunctioning during that process. Few times I had to reopen my project so that Android Studio can understand properly what is going on. “Refresh all Gradle projects” button has been life saver for me.😉

But don’t worry, Just follow the steps with me and you will be just fine.

Migrate to Gradle Kotlin Script

A nice thing about Kotlin build script is you don’t have to do the extra setup for enabling it. Just rename .gradle file to .gradle.kts file extension and Gradle will consider it as a Kotlin script. Please note that following the steps below in sequence is highly important to avoid intermediate Gradle issues.

To make sure that everything works fine, update your gradle to version 4.10 or higher(5.2.1 is latest at the time of writing this post). To do so, go to your project’s gradle-wrapper.properties and check distributionUrl for the current version. make sure it looks like below:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip

Step-1 Convert Settings.gradle File

Let’s start with settings.gradle file by renaming (Shift + F6) it to settings.gradle.kts. Now that this file is a Kotlin script, include will behave as a function and “:app” will be the string argument.

Before

include ':app'

After

include(":app")

✏️Note that in Groovy, you were able to write single quotes(‘’) in place of double quotes(“”) but in Kotlin, you must have to use double quotes only.

Now that you have converted it in Kotlin, Gradle will identify it accordingly and will process it as Kotlin script. Just sync with Gradle files.

Step-2 Convert Project’s build.gradle File

Rename project level build.gradle to build.gradle.kts. The main difference here is in classpath and in clean task.

classpath is now a function in Kotlin which takes a string argument as shown below:

Before

dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
}

After

dependencies {
classpath("com.android.tools.build:gradle:3.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21")
}

clean task will no longer be written in Groovy. This is how it looks in Kotlin:

Before

task clean(type: Delete) {
delete rootProject.buildDir
}

After

tasks.register("clean",Delete::class){
delete(rootProject.buildDir)
}

Another thing that can change is that if you have any repositories with url in repositories block. You can change it like this:

Before

repositories {
google()
jcenter()
maven{ url 'https://jitpack.io' }
}

After

repositories {
google()
jcenter()
maven { url = uri("https://jitpack.io") }
}

That’s it! The file is now completely in Kotlin. If you have some other configurations then you can easily convert it into Kotlin with the help of Auto Completion. If you don’t know how to implement something, you can always navigate to the source code. That’s the beauty of it.

Here is the whole build.gradle.kts file:

buildscript {
repositories {
maven { url = uri("https://jitpack.io") }
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21")
}
}
allprojects {
repositories {
google()
jcenter()
maven { url = uri("https://jitpack.io") }
}
}
tasks.register("clean",Delete::class){
delete(rootProject.buildDir)
}

You’ll be able to sync your project after completing this step.

Step-3 Convert App Level build.gradle File

Here comes a little bit messy part😵. Open app level build.gradle file and rename it to build.gradle.kts. Don’t try to sync now. It will show lots of errors but don’t worry, we’re going to remove all the errors one by one. Let’s start at the top.

In Groovy, every plugin was being applied individually whereas Kotlin provides plugins{} block to apply all the plugins within a single block.

Before

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'

After

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

Here, id() and kotlin() are functions which are used to apply plugins.

id() is used to apply any plugin. All the plugins can be applied using id().

Plugins which are specific to Kotlin can also be applied using kotlin() function. That’s cool😎

Note that when you use kotlin() function, the kotlin prefix will be removed from plugin name and the dash(-) will be replaced by dot(.). For the sake of simplicity, you can use id() function instead.

Note these points to convert this block in Kotlin:

  • compileSdkVersion is a function.
  • applicationId is a property.
  • minSdkVersion and targetSdkVersion are functions too.
  • versionCode and versionName are properties again.

According to the above points, this block will look like this:

Before

android {
compileSdkVersion 28
defaultConfig {
applicationId "com.birjuvachhani.gradlekotlindsldemo"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
...
...
}

After

android {
compileSdkVersion(28)
defaultConfig {
applicationId = "com.birjuvachhani.gradlekotlindsldemo"
minSdkVersion(19)
targetSdkVersion(28)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
...
...
}

buildTypes{ } block is a bit tricky. A function getByName(String) is used to get a build type.

minifyEnabled is a property with name isMinifyEnabled.

proguardFiles and getDefaultProguardFile are functions.

This is how it will look like:

Before

android {
...
...
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

After

android {
...
...
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}

There should be only one block left (if you don’t have any extra configs hopefully😬) that is the dependencies{} block.

Here, implementation, kapt, api, testImplementation, androidTestImplementation, etc are functions.

The fileTree in implementation() is also a function which takes a map as an argument. Here’s how it will look like:

Before

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21"
implementation 'androidx.appcompat:appcompat:1.1.0-alpha02'
implementation 'androidx.core:core-ktx:1.1.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.2-alpha01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01'
}

After

dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21")
implementation("androidx.appcompat:appcompat:1.1.0-alpha02")
implementation("androidx.core:core-ktx:1.1.0-alpha04")
implementation("androidx.constraintlayout:constraintlayout:1.1.3")
testImplementation("junit:junit:4.12")
androidTestImplementation("androidx.test:runner:1.1.2-alpha01")
androidTestImplementation("androidx.test.espresso:espresso-core:3.1.2-alpha01")
}

Here is the whole app level build.gradle.kts file:

plugins {
id("com.android.application")
kotlin("android")
kotlin("android.extensions")
}
android {
compileSdkVersion(28)
defaultConfig {
applicationId = "com.birjuvachhani.gradlekotlindsldemo"
minSdkVersion(19)
targetSdkVersion(28)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21")
implementation("androidx.appcompat:appcompat:1.1.0-alpha02")
implementation("androidx.core:core-ktx:1.1.0-alpha04")
implementation("androidx.constraintlayout:constraintlayout:1.1.3")
testImplementation("junit:junit:4.12")
androidTestImplementation("androidx.test:runner:1.1.2-alpha01")
androidTestImplementation("androidx.test.espresso:espresso-core:3.1.2-alpha01")
}

Hell Yeah! Sync the project (Hopefully it will compile, let’s have some faith in Gradle). There you go, your project is converted in Kotlin build scripts. Say goodbye to Groovy!

If you’re reading this and you have made it then you’d be probably like this:

or maybe this (I don’t know how you function, it’s an educated guess):

It depends on you.😄 It’s just a matter of time, Gradle will provide kotlin script support by default. That means this all will be directly generated for you. How amazing is that! Till then, Happy coding folks!

Here is the sample project on github you can refer for this tutorial.

https://github.com/BirjuVachhani/gradle-kotlin-dsl-demo

MindOrks

Our community publishes stories worth reading on Android…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store