How to Convert Android Gradle Groovy to KTS?
Tags: android, kotlin, beginners, gradle
Published: 2022-12-30 23:00:00

**Step-by-step guide to convert or migrate your Android project's Gradle script from Groovy script to Kotlin script (KTS)**

## Introduction

Gradle is the build automation tool. Android Studio uses Gradle to build the apps. Gradle can be written in these 2 domain-specify languages (DSL):

* Groovy Script
    
* Kotlin Script (KTS)
    

### What is Groovy?

Groovy is a dynamically typed language, which means the variable types are known at run time. This is usually an interpreter or scripting language.

### What is Kotlin?

Kotlin is a statically typed language, which means the variable types are known at compile time. This is usually for general-purpose programming language. However, for this Gradle building context, Kotlin is considered as a script. It is called Kotlin Script (KTS)

> Both Groovy and Kotlin can run on Java Virtual Machine (JVM).

### Why Convert Groovy to KTS?

This is what [official documentation](https://developer.android.com/studio/build/migrate-to-kts) says:

> In the future, KTS will be preferred over Groovy for writing Gradle scripts because Kotlin is more readable and offers better compile-time checking and IDE support.

But it also says:

> builds using KTS tend to be slower than builds using Groovy

It sounds to me, it is not ready yet? Probably that's the reason why the default Gradle script setup from Android Studio is Groovy and not KTS.

If build performance is not an issue, maybe you can consider migrating to KTS? But who doesn't want a faster build?

So I think conversion to KTS is probably for education purposes or preparing yourself for the future. The following guide provides step-by-step instructions on what I did to convert [my template app](https://vtsen.hashnode.dev/clean-empty-jetpack-compose-app-template) to use KTS.

## Step-by-step Guide

* `*.gradle` extension is for Groovy script
    
* `*.gradle.kts` extension is for Kotlin script.
    

### 1\. Rename settings.gradle to settings.gradle.kts

You get the following error.

> Function invocation 'include(...)' expected

To fix that, you change

```kotlin
include ':app'
```

to

```kotlin
include ("app")
```

You get this message on the top of your IDE.

> Multiple script definitions are applicable to this script. KotlinSettingScript is used

It looks like a [known issue](https://youtrack.jetbrains.com/issue/KTIJ-18274), but it is not a show-stopper.

You also have this message which will be gone after you convert all the Groovy scripts to KTS.

> Code insight unavailable (script configuration wasn't received) - Add to standalone scripts

### 2\. Rename build.gradle to build.gradle.kts

You get this error:

> Unexpected tokens (use ';' to separate expressions on the same line)

To fix that, you change

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

to

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

> **[Updated - Jan 3, 2023]:** It looks like this "clean" task is no longer needed because it has been implemented by default in Gradle. So I have removed this task in build.gradle / build.gradle.kts.

After that, you compile and get the same error:

> Unexpected tokens (use ';' to separate expressions on the same line)

To fix that, you replace

```kotlin
buildscript {
    ext {
        android_gradle_plugin_version = '7.2.2'
    }
}

plugins {
    id 'com.android.application' version "$android_gradle_plugin_version" apply false
    id 'com.android.library' version "$android_gradle_plugin_version" apply false
    id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
}
```

with

```kotlin
buildscript {
    val android_gradle_plugin_version by extra("7.2.2")
}

plugins {
    id("com.android.application") version "${extra["android_gradle_plugin_version"]}" apply false
    id("com.android.library") version "${extra["android_gradle_plugin_version"]}" apply false
    id("org.jetbrains.kotlin.android") version "1.7.0" apply false
}
```

It can build and run successfully. However, there is still this error message:

> val ExtensionAware.extra: ExtraPropertiesExtension' can't be called in this context by implicit receiver. Use the explicit one if necessary

It looks like this is [plugins DSL limitations - constrained syntax](https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax) which doesn't allow you to access the variable in the plugins block - does not support arbitrary code.

> The plugins {} block does not support arbitrary code. It is constrained...

So just hard code it instead:

```kotlin
buildscript {
}

plugins {
    id("com.android.application") version "7.2.2" apply false
    id("com.android.library") version "7.2.2" apply false
    id("org.jetbrains.kotlin.android") version "1.7.0" apply false
}
```

> FYI - I don't have the `compose_version` variable here because I've moved it to the `app\build.gradle`

### 3\. Rename app\\build.gradle to app\\build.gradle.kts

If you use the ["Refactor -&gt; Rename..."](https://vtsen.hashnode.dev/my-most-used-android-studio-shortcut-keys#heading-4-refactor-andgt-rename-shift-f6), it automatically updates the comment in `proguard-rules.pro` file.

You will get errors, and here are the fixes.

**Change plugins**

```kotlin
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}
```

to

```kotlin
plugins {
    id ("com.android.application")
    id ("org.jetbrains.kotlin.android")
}
```

**Change compile Sdk & defaultConfig**

```kotlin
android {
    compileSdk 32

    defaultConfig {
        applicationId "vtsen.hashnode.dev.newemptycomposeapp"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }
    }
    /*...*/
}
```

to

```kotlin
android {
    compileSdk = 32

    defaultConfig {
        applicationId = "vtsen.hashnode.dev.newemptycomposeapp"
        minSdk = 21
        targetSdk = 32
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }
    /*...*/
}
```

**Change buildTypes and compleOptions**

```kotlin
android {
    /*...*/
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile(
                'proguard-android-optimize.txt'), 
                    'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    /*...*/
}
```

to

```kotlin
android {
    /*...*/
    buildTypes {
        release {
            isMinifyEnabled  = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                    "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    /*...*/
}
```

> **Note:** `minifyEnabled` is renamed to `isMinifyEnabled`

**Change buildFeatures and composeOptions**

```kotlin
android {
    /*...*/
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion '1.2.0'
    }
    /*...*/
}
```

to

```kotlin
android {
    /*...*/
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.2.0"
    }
    /*...*/
}
```

**Change packagingOptions and namespace**

```kotlin
android {
    /*...*/
    packagingOptions {  
	    resources {  
            excludes += '/META-INF/{AL2.0,LGPL2.1}'  
        }  
    }
    
    namespace 'vtsen.hashnode.dev.newemptycomposeapp'
}
```

to

```kotlin
android {
    /*...*/
    packagingOptions {  
        resources {  
            excludes.add("/META-INF/{AL2.0,LGPL2.1}")  
        }  
    }
        
    namespace = "vtsen.hashnode.dev.newemptycomposeapp"
}
```

**Change dependencies**

```kotlin
dependencies {
    implementation 'androidx.core:core-ktx:1.8.0'
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
    implementation 'androidx.activity:activity-compose:1.5.1'

    def compose_version = '1.2.1'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"

    implementation "com.google.accompanist:accompanist-systemuicontroller:0.24.2-alpha"
}
```

to

```kotlin
dependencies {  
  
    implementation("androidx.core:core-ktx:1.8.0")  
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")  
    implementation("androidx.activity:activity-compose:1.5.1")  
  
    val composeVersion = "1.2.1"  
    implementation("androidx.compose.ui:ui:$composeVersion")  
    implementation("androidx.compose.material:material:$composeVersion")  
    implementation("androidx.compose.ui:ui-tooling-preview:$composeVersion")  
    debugImplementation("androidx.compose.ui:ui-tooling:$composeVersion") 
  
    implementation("com.google.accompanist:accompanist-systemuicontroller:0.24.2-alpha")  
}
```

> `composeVersion` is used instead of `compose_version` due to the naming convention in Kotlin

## Build Time Comparisons

I perform a quick built-time testing, the difference is not significant. Both build times are about the same. Probably this project is too simple, so the difference is not obvious.

| Build Time | First Compile (clean build) | Second Compile (clean build) |
| --- | --- | --- |
| Groovy | 6 seconds | 2-3 seconds |
| KTS | 6 seconds | 2-3 seconds |

## Source Code

* GitHub Repository: [Demo\_CleanEmptyCompose](https://github.com/vinchamp77/Demo_CleanEmptyCompose)
    
* Conversion: [Diff](https://github.com/vinchamp77/Demo_CleanEmptyCompose/compare/186d8881181cace3c1d8303db01c43e58cad2e3e..2e0a4e1fa96f5d1b967e89e2e0c88052e7a3d9eb)

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/how-to-convert-android-gradle-groovy-to-kts)*.