Using Gradle Script Kotlin for Android

As you know, we use Groovy to write our Gradle build scripts and it has pros and cons. Groovy is a dynamic language which means that it’s not statically typed, making difficult to write or modify our gradle scripts without making many mistakes as we don’t have autocomplete there.

Last year, Gradle decided to start using Kotlin to writing Gradle build scripts creating, what they call, Gradle Kotlin Script. The project is moving fast (0.9.0 version at the time of writing this article) but, on the other hand, there is practically no documentation.

So, I want to show you how to use Gradle Kotlin Script to create Gradle build scripts written in Kotlin in one Android project.

First Step: Adding Gradle Kotlin Script to the project

We need an Android project to configure the Gradle Kotlin Script on, so I have created a new empty basic project called gradle-script-kotlin-example with Android Studio. The project looks like this way after the creation wizard:

Project structure

It is pretty easy, only a matter of completing the creation wizard. Now, we have to add Gradle Kotlin Script to the project, it’s not trivial but it’s not too complicated.

At this moment, Gradle Kotlin Script is bundled inside a Gradle distribution so we need to change the Gradle distribution URL modifying the file gradle/wrapper/gradle-wrapper.properties. It should be something like:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://repo.gradle.org/gradle/dist-snapshots/gradle-script-kotlin-4.0-20170518042627+0000-all.zip

This distributionUrl contains a special Gradle snapshot which also includes Gradle Script Kotlin 0.9.0.

Second Step: Creating our first Gradle build script written in Kotlin

As you know, the common filename for a Gradle build script is gradle.build. Instead, we should use the kts extension when using Kotlin Script.

We’re going to migrate the build.gradle file located at the root of the project to Kotlin. Currently, it should look this way:

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
}
}
allprojects {
repositories {
jcenter()
}
}

It’s time to migrate it. First, you can safely delete it. Now, create a new file called build.gradle.kts and write the following:

import org.gradle.script.lang.kotlin.repositories

buildscript {

repositories {
jcenter()
}

dependencies {
classpath("com.android.tools.build:gradle:2.3.2")
}
}

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

Voilà! Our first Gradle build script written in Kotlin!. You can see that both are very similar but there are some differences, for example, classpath contains parenthesis which is telling us we are using Kotlin syntax.

Before trying to perform a Gradle sync, we need to take a last step. We need to add a special JSON file to tell some configurations to Gradle Script Kotlin. Create and edit the file buildSrc/src/gradle-script-kotlin/resources/project.schema.json with the following content:

{
":": {
"conventions": {
},
"extensions": {
"ext": "org.gradle.api.plugins.ExtraPropertiesExtension"
}
},
":app": {
"conventions": {
"base": "org.gradle.api.plugins.BasePluginConvention",
"java": "org.gradle.api.plugins.JavaPluginConvention"
},
"extensions": {
"ext": "org.gradle.api.plugins.ExtraPropertiesExtension",
"defaultArtifacts": "org.gradle.api.internal.plugins.DefaultArtifactPublicationSet",
"reporting": "org.gradle.api.reporting.ReportingExtension",
"android": "com.android.build.gradle.AppExtension",
"kotlin": "org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension",
"kapt": "org.jetbrains.kotlin.gradle.plugin.KaptExtension"
}
}
}

It’s a bit of black magic because there is no documentation about it but we can realize we are configuring the plugins that Gradle Script Kotlin have to use for the root project and for the app module here.

Finally, if you try to perform a Gradle sync it will fail because the project is not finding our new Gradle build script, it’s expecting to run the previousbuild.gradle. We only have to add one line to settings.gradle in order to make Gradle using the build.gradle.kts file as build script instead of the previous one. Edit the settings.gradle file and add rootProject.buildFileName = 'build.gradle.kts:

rootProject.buildFileName = 'build.gradle.kts'

include ':app'

Note: This step is optional since Gradle Kotlin Script 0.9.0 but I can tell you it doesn’t work for me without adding the line.

Note 2: The project won’t sync on Android Studio saying the project is not a Gradle project, but I found a workaround. Create an empty build.gradle file (with no content) at the root of the project and Android Studio will start to sync without problems.

Note 3: Sometimes Android Studio doesn’t detect the changes in your kts files, you need to restart the IDE to fix the problem. It’s a known issue with Gradle Kotlin Script and it will be fixed in following versions.

And last but not least, you have autocomplete and source navigation in the Gradle Kotlin scripts now!.

Autocomplete and source navigation

Bonus Step: Using a custom class to group our dependencies

We can go further and use the power of Kotlin to group our dependencies to be used with autocomplete.

The idea is to use buildSrc feature from Gradle to create a custom class where we’ll store the configuration. Understanding buildSrc is out of the scope of this article but, if you are interested, you can learn more here.

As we are on fire with Kotlin we want also use Kotlin to write this class so the first thing we have to do is enable Gradle Script Kotlin for buildSrc. Same as before, create and edit the buildSrc/gradle/wrapper/gradle-wrapper.properties file and add this content:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://repo.gradle.org/gradle/dist-snapshots/gradle-script-kotlin-4.0-20170518042627+0000-all.zip

Also, create and edit the buildSrc/settings.gradle to add the following line:

rootProject.buildFileName = 'build.gradle.kts'

Finally, create the buildSrc/build.gradle.kts file with the next content:

buildscript {
repositories {
gradleScriptKotlin()
}
dependencies {
classpath(kotlinModule("gradle-plugin"))
}
}
apply {
plugin("kotlin")
}
dependencies {
compile(gradleScriptKotlinApi())
compile(kotlinModule("stdlib"))
}
repositories {
gradleScriptKotlin()
}

Once we have Gradle Kotlin Script configured in buildSrc we can start to create our new class where we will store the project configuration and dependencies. I’ve called this class: ProjectConfiguration (very original, right?).

This class will contain three objects:

  • BuildPlugins. Contains the android gradle and kotlin gradle build plugins.
  • Android. Contains build tools version, minSdk version and this kind of things.
  • Libs. Contains app module dependencies.
  • TestLibs. Contains app module test dependencies

You are going to understand it better when you see the file but in order to simplify the article, I will show you only the BuildPlugins section.

Create the builSrc/src/main/kotlin/ProjectConfiguration.kt file:

class ProjectConfiguration(
val buildPlugins: BuildPlugins
)
class BuildPlugins(
val androidGradle: String,
val kotlinGradlePlugin: String
)

I like to create a gradle file where I write all gradle plugins, dependencies versions or common configuration. I usually call the file dependencies.gradle but, as we are using Gradle Kotlin Script we have to call it dependencies.gradle.kts:

import org.gradle.script.lang.kotlin.extra
import org.gradle.script.lang.kotlin.getValue
import org.gradle.script.lang.kotlin.setValue

var projectConfiguration: ProjectConfiguration by extra

val kotlinVersion = "1.1.2"
val androidGradleVersion = "2.3.2"

projectConfiguration = ProjectConfiguration(
BuildPlugins(
"com.android.tools.build:gradle:$androidGradleVersion",
"org.jetbrains.kotlin:kotlin-gradle plugin:$kotlinVersion"
)
)

The idea is to create a ProjectConfiguration instance with the right content and store it in the extra container. This extra container is used to share data between different Gradle scripts.

Once, we have a configured instance of ProjectConfiguration we have to use it. If you remember, the Android Gradle Plugin is used in the build.gradle.kts file at the root of the project. Open it and change its content to the following:

import org.gradle.script.lang.kotlin.applyFrom
import org.gradle.script.lang.kotlin.extra
import org.gradle.script.lang.kotlin.repositories

buildscript {
repositories {
jcenter()
}

dependencies {
applyFrom("dependencies.gradle.kts")

val projectConfiguration: ProjectConfiguration by extra

classpath(projectConfiguration.buildPlugins.androidGradle)
classpath(projectConfiguration.buildPlugins.kotlinGradlePlugin)
}
}

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

That’s all! We have our build plugins statically typed and organized in one Kotlin file. And, more important, we can write the build script using autocomplete.

You’ll never make a mistake when writing dependencies

The full example project is already available on GitHub: https://github.com/arturogutierrez/gradle-script-kotlin-example

Feel free to take a look, fork it, comment or ask questions, I’m glad to help.


Thanks for reading this article. If you liked or found helpful this article remember to click ❤ below to recommend it. It helps me a lot.

Also, you can follow me on Twitter, Github, Facebook or Linkedin.