Android — Migrating to Kotlin Script

Introduction

This article will cover my experience on migrating one simple project from Groovy Gradle to Kotlin Script.
It will cover the setup and process having it working fine to start doing stuff over Kotlin Script in your project. 🎉

Android Experiment

The project I’m going to use for this post will be a simple Android app that uses the SpaceX API (https://github.com/r-spacex/SpaceX-API). I’m going to split this project into modules to make it a little bit more complex.

So for the first part of our experiment, I’m going to give an overview of how I set up Kotlin Script in an Android project, for more details please take a look at these references:

Documentation: https://bit.ly/2TjDEwO
The New Way of Writing Build Gradle with Kotlin DSL: https://bit.ly/388T1fs
I hated Gradle! Kotlin and the buildSrc Plugin made me love it: https://bit.ly/2tlMM9B

Github Project link:

Disclaimer: I used the Android Studio 4.0 Preview for this project to use the Jetpack Compose.

Kotlin Script

A few years ago, Gradle announced support for Kotlin, which I truly believe made almost all Android developers excited about it. Why?! Because it allows us to code on Gradle using the same language we use on our Android codebase.

The “amazing” buildSrc

One of the most useful things about using Gradle with Kotlin is the buildSrc folder. Long short story, everything inside this folder will be built first and will be available to be used on build.gradle.kts. You will find a great and detailed post about it on the already mentioned “I hated Gradle! Kotlin and the buildSrc Plugin made me love it”

Setup

Before we proceed, we must rename our gradle files to use the .kts extension. So, for this example, we’re going to modify the following files:

  • settings.gradle ===> settings.gradle.kts
  • build.gradle ===> build.gradle.kts

Settings Gradle

The settings Gradle file is not that different, the main difference is that when using Kotlin Script we must replace all single quote signs (‘) by double quote signs (“) and the function calls must use parenthesis.

Top-Level Build Gradle

So, let’s point the differences between these Gradle files. The first thing is that the maven call is an extension function declared on RepositoryHandlerExtensions for the RepositoryHandler Java Interface

fun RepositoryHandler.maven(url: Any) =
maven { it.setUrl(url) }

Also, the classpath must be defined as a function, since it’s using an extension function declared on ScriptHandlerScope class for the DependencyHandler

fun DependencyHandler.classpath(dependencyNotation: Any): Dependency? =
add(CLASSPATH_CONFIGURATION, dependencyNotation)

Another interesting point is that we can use the kotlin function on KotlinDependencyExtensions to declare dependencies defined under “org.jetbrains.kotlin:kotlin-”

fun DependencyHandler.kotlin(module: String, version: String? = null): Any =
"org.jetbrains.kotlin:kotlin-$module${version?.let { ":$version" } ?: ""}"

Finally, the clean task definition, in case of Kotlin Script we use the register extension function from the tasks declared on ProjectDelegate class

inline fun <T : org.gradle.api.Task> org.gradle.api.tasks.TaskContainer.`register`(`name`: String, `type`: kotlin.reflect.KClass<T>, `configurationAction`: org.gradle.api.Action<in T>): org.gradle.api.tasks.TaskProvider<T> =
`register`(`name`, `type`.java, `configurationAction`)

Application Build Gradle

Despite the basic modifications like swapping quotation marks and call functions using parenthesis (In case of attributes must use the equal sign, it’s hard to know which are functions and which are attributes, I did it empirically), we must apply the following changes:

  • Apply plugins using the plugins closure, it’s possible to declare plugins using convention objects, but according to the Gradle documentation (https://bit.ly/2tjJIKX):

Please avoid using convention objects when writing new plugins. The long term plan is to migrate all Gradle core plugins to use extensions and remove the convention objects altogether.

  • The Build types declaration which needs to use the getByName function to retrieve types according to the build type name provided
  • The dynamicFeatures attribution, which needs to declare a mutable set to assign
  • For the dependencies, I declared a separate kotlin file and split into api, implementation, testImplementation and androidTestImplementation. These dependencies are defined under buildSrc folder (we could do the same by applying Groovy Gradle files).

After all these modifications you will be able to build your project using Kotlin Script 🎉 I hope it helped you and see you next time.

--

--

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