Introduction to the

This article assumes that you already have the foundation of Kotlin. If you are not familiar with Kotlin, you can go to my previous post – “Kotlin Jetpack Combat”.

This article will lead you step by step to Demo project Gradle script into Kotlin DSL, let us practice together!

The body of the

1. Advantages of Kotlin writing Gradle scripts

Kotlin Groovy
Automatic code completion support Does not support
Type safe or not is not
The source code navigation support Does not support
refactoring Automatic link Manually modify

2. Preparation

  • Update the Android Studio version to the latest
  • Clone our Demo project locally and open it with Android Studio:

Github.com/chaxiu/Kotl…

  • Switch to branch:chapter_02_kotlin_dsl_training
  • Readers are strongly encouraged to practice along with this article. Practice is the essence of this article.

3. Start refactoring

3 to 1. The willSingle quotesreplaceDouble quotation marks

Replace before:

apply plugin:'com. Android. Application'Copy the code

After the replacement:

apply plugin: "com.android.application"
Copy the code

Summary:

  • Instead of changing the Gradle file extension, use Android Studio instead.
  • Why can be directly replaced? Because Grooovy and Kotlin have similar syntax for string definitions:Double quotation marksRepresents a string.
  • So why replace? becauseSingle quotes Double quotation marksIn Groovy it’s all defined strings, whereas in KotlinSingle quotesDefinition isA single character.Double quotation marksIs defining a string.

See my GitHub Commit for more details

3-2. Modify the Gradle file extension

    1. builde.gradle –> build.gradle.kts
    1. settings.gradle –> settings.gradle.kts
    1. Sync start!

Script compilation errors: Line 1: include “:app” Unexpected tokens (use ‘; ‘ > to separate expressions on the same line) Line 1: include “:app” Function invocation ‘include(…) ‘ > expected 2 errors

Don’t panic! Reporting mistakes is not terrible, not reporting mistakes is terrible! At least we know what went wrong. The error log tells us that the problem is here:

// settings.gradle
include ":app"
Copy the code

Command + left mouse click include to see the source code implementation:

override fun include(vararg projectPaths: String?). =
    delegate.include(*projectPaths)
Copy the code

Hey! Settings. gradle includes are essentially method calls. Function Invocation ‘include(…) ‘> < p style = “margin-bottom: 0pt; margin-bottom: 0pt; That is, when we change the Gradle extension, the IDE considers it a Kotlin statement. Include “:app” uses Groovy syntax.

This would be fine:

// Call the include method and pass in a string ":app"
include(":app")
Copy the code

Then repeat this step: Sync –> error –> Command + left mouse button to view the source code

Modify before:

dependencies {
    classpath "Com. Android. Tools. Build: gradle: 4.0.0"
}
Copy the code

Revised:

dependencies {
    classpath("Com. Android. Tools. Build: gradle: 4.0.0")}Copy the code

3-3. What if I encounter an unresolvable error?

For example: If you continue Sync, the error is here:

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

e: /KotlinJetpackInAction/build.gradle.kts:19:16: Expecting ‘)’

e: .. /KotlinJetpackInAction/build.gradle.kts:19:16: Unexpected tokens (use ‘; ‘ to separate expressions on the same line) e: .. /KotlinJetpackInAction/build.gradle.kts:20:23: Expecting an element e: .. /KotlinJetpackInAction/build.gradle.kts:20:32: Expecting an element e: .. /KotlinJetpackInAction/build.gradle.kts:19:1: Function invocation ‘task(…) ‘ expected e: .. /KotlinJetpackInAction/build.gradle.kts:19:1: None of the following functions can be called with the arguments supplied: public abstract fun task(p0: String!) : Task! defined in org.gradle.api.Project public abstract fun task(p0: String! , p1: Closure<(raw) Any! >! : Task! defined in org.gradle.api.Project public abstract fun task(p0: String! , p1: Action

! : Task! defined in org.gradle.api.Project public abstract fun task(p0: (Mutable)Map

! , p1: String!) : Task! defined in org.gradle.api.Project public abstract fun task(p0: (Mutable)Map

! , p1: String! , p2: Closure<(raw) Any! >! : Task! defined in org.gradle.api.Project e: .. /KotlinJetpackInAction/build.gradle.kts:19:12: Function invocation ‘type(…) ‘ expected e: .. /KotlinJetpackInAction/build.gradle.kts:19:12: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public inline fun ObjectConfigurationAction.type(pluginClass: KClass<>): ObjectConfigurationAction defined in org.gradle.kotlin.dsl e: .. /KotlinJetpackInAction/build.gradle.kts:20:5: Function invocation ‘delete(…) ‘ expected e: .. /KotlinJetpackInAction/build.gradle.kts:20:12: Unresolved reference: rootProject
!>
!>

Good terrible, this time reported a lot of mistakes, and look very strange. How to do? Don’t panic! Migrating Build Logic from Groovy to Kotlin has a manual for Migrating

Is the migration guide too long? Or pure English? Don’t be afraid! Kotlin officially has a migration case for us: Kotlin-Dsl-samples: Hello-Android

Look! The migration case tells us how to change the clean Task:

/ / specific look here: https://github.com/gradle/kotlin-dsl-samples/blob/master/samples/hello-android/build.gradle.kts
tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}
Copy the code

3-4. Referencekotlin-dsl-samplesContinue to modify

Modify before:

apply plugin: "com.android.application"
Copy the code

Revised:

plugins {
    id("com.android.application")}Copy the code

Modify before:

android {
    compileSdkVersion 29

    defaultConfig {
        applicationId "com.boycoder.kotlinjetpackinaction"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"}}}Copy the code

Revised:

android {
    compileSdkVersion(29)

    defaultConfig {
        applicationId = "com.boycoder.kotlinjetpackinaction"
        minSdkVersion(21)
        targetSdkVersion(29)
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

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

Modify before:

dependencies {
    // Omit part...
    implementation fileTree(dir: "libs".include: ["*.jar"])
    implementation "Androidx. Appcompat: appcompat: 1.1.0." "
    testImplementation "Junit: junit: 4.12"
    androidTestImplementation "Androidx. Test. Ext: junit: 1.1.1"
    annotationProcessor "Com. Making. Bumptech. Glide: the compiler: 4.8.0"
}
Copy the code

Revised:

dependencies {
    // Omit part...
    implementation(fileTree(mapOf("dir" to "libs"."include" to listOf("*.jar"))))
    implementation("Androidx. Appcompat: appcompat: 1.1.0." ")
    testImplementation("Junit: junit: 4.12")
    androidTestImplementation("Androidx. Test. Ext: junit: 1.1.1")
    annotationProcessor("Com. Making. Bumptech. Glide: the compiler: 4.8.0")}Copy the code

See my Github Commit for details

3-5 And you’re done!

Now we can have fun writing Gradle scripts with Kotlin. So, is this the end of the article? Don’t. This article is based on actual practice. We just finished reconstructing the project using Kotlin DSL.

4. Kotlin DSL Practice — Dependency management

4-1. Dependency management in the Groovy era

We used to define dependencies this way:

// Builde. gradle in the root directory
ext {
  versions = [
    support_lib: "28.0.0".glide: "4.8.0"
  ]
  libs = [
    support_annotations: "com.android.support:support-annotations:${versions.support_lib}".glide: "com.github.bumptech.glide:glide:${versions.glide}"]}Copy the code

Then use it like this:

// builde.gradle in app directory
implementation libs.support_annotations
implementation libs.glide
Copy the code

4-2. Dependency management in the Kotlin era

The Kotlin DSL manages dependencies in a number of ways, but I’m going with the relatively mainstream approach: manage them in the buildSrc directory. Details can be found in the official Gradle Documentation

Simple translation:

When running Gradle, it checks to see if there is a buildSrc directory in the project root directory. If so, all scripts in this directory are automatically added to the project’s environment variable (classpath).

Using the above mechanism, we can define all dependencies as constants in the buildSrc directory, which we can then use directly in our projects.

The specific structure is as follows:

Projectproperties.kt defines project-specific properties:

// projectproperties.kt defines project-specific properties
object ProjectProperties {
    const val compileSdk = 29
    const val minSdk = 21
    const val targetSdk = 29

    const val applicationId = "com.boycoder.kotlinjetpackinaction"
    const val versionCode = 1
    const val versionName = "1.0.0"

    const val agpVersion = "4.0.0"
}
Copy the code

Libs.kt defines all dependencies:

object Libs {
    const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompat}"
    const val constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}"    
}
Copy the code

Versions.kt defines the version numbers of all dependent libraries:

object Versions {
    const val appCompat = "1.1.0"
    const val constraintlayout = 1.1.3 ""
}
Copy the code

The corresponding build.gradle. KTS changes as follows:

dependencies {
    implementation(fileTree(mapOf("dir" to "libs"."include" to listOf("*.jar"))))
    implementation(Libs.appCompat)
    implementation(Libs.constraintlayout)
}
Copy the code

For details, see Github Commit:

Look, now our Gradle code will have autocomplete prompt.

How sweet!

At the end

Note: It’s easy to completely replace Groovy with Kotlin DSL in a new project, but not so easy with an older project, as the migration of Kotlin DSL potholes will be covered later.

In the next section, I’m going to rebuild Kotlin step by step from the Java code in the Demo project.

Now that you’ve seen it, give it a thumbs up!

The next chapter — — >The Triple Realm of Kotlin Programming

Directory – >Kotlin Jetpack In Action