Writing gradle scripts using Kotlin
summary
IDE support
Build import | Syntax highlighting 1 | Semantic editor 2 | |
---|---|---|---|
IntelliJ IDEA | ✓ | ✓ | ✓ |
Android Studio | ✓ | ✓ | ✓ |
Eclipse IDE | ✓ | ✓ | ✖ |
CLion | ✓ | ✓ | ✖ |
Apache NetBeans | ✓ | ✓ | ✖ |
Visual Studio Code (LSP) | ✓ | ✓ | ✖ |
Visual Studio | ✓ | ✖ | ✖ |
- Kotlin syntax highlighting in Gradle Kotlin DSL scripts
- Gradle Kotlin DSL scripts supports code completion, navigation to source code, document viewing, refactoring, etc;
Kotlin DSL script naming
name
Groovy DSL script file usage gradle extension
Kotlin DSL script file usage gradle.kts extension file name
Activate and use kotlin dsl
- Name the script file gradle.kts can be activated. Also applicable to settings file (settings.gradle.kts) and initialization scripts.
- For better IDE support, the following naming convention is recommended:
- The settings script is named * settings.gradle.kts (including all scripts introduced from the settings script)
- initialization scripts Press * init.gradle.kts is named after the naming pattern, or simply named init gradle. kts.
- The kotlin DSL build script implicitly imports the following contents:
- default Gradle API imports
- At org gradle. kotlin. DSL and org gradle. kotlin. dsl. plugins. Kotlin DSL API in DSL package
Read runtime properties from kotlin
gradle has two runtime properties:
Project properties
You can access through kotlin's proxy properties:
build.gradle.kts
// Attribute must exist val myProperty: String by project // Property can not exist val myNullableProperty: String? by project
extra attribute
The extra attribute is implemented anywhere ExtensionAware All objects of the interface can be accessed;
build.gradle.kts
val myNewProperty by extra("initial value") // ❶ val myOtherNewProperty by extra { "calculated initial value" } //❷ val myProperty: String by extra // ❸ val myNullableProperty: String? by extra // ❹
❶ create a new extra property named myNewProperty in the current context (currently in project) and initialize its value as "initial value"
❵the same as ❶, but the initial value of the attribute is calculated through the lamdba expression;
❸ bind the property in the current context (currently project) to the myProperty property property;
❹ is the same as ❸, but the allowed value is null;
Access rootProject properties in subprojects
val myNewProperty: String by rootProject.extra
By is the keyword of kotlin, which means provided by, that is, the attribute is represented by some other object
Defining and using attributes in tasks
The task also inherits ExtensionAware, so we can also use the extra attribute in the task
tasks { test { val reportType by extra("dev") doLast { // Use 'suffix' for post processing of reports } } register<Zip>("archiveTestReports") { val reportType: String by test.get().extra archiveAppendix.set(reportType) from(test.get().reports.html.destination) } }
Define and access extra attributes through map format
extra["myNewProperty"] = "initial value" // ❶ tasks.create("myTask") { doLast { println("Property: ${project.extra["myNewProperty"]}") // ❷ } }
Migrate gradle build logic to Kotlin
Reference documents:
- Migrating build logic from Groovy to Kotlin (gradle.org)
- Android Gradle scripts migrated from Groovy to Kotlin DSL - Paladin wind - blog Park (cnblogs.com)
Preparing groovy scripts
- The quotation marks are unified into double quotation marks
- Method call with parentheses
- Assignment plus equal sign
Uniform quotation marks
-
Use the ⌘ ⇧ R shortcut key to call up the search and replace tool window, and set the file matching to gradle, and then replace all single quotes with double quotes.
-
When finished, use the gradle file again to synchronize the project to see if there are any errors
Assignment and attribute modification
- Add an equal sign to all assignment operations
- Add parentheses to all function call operations
Here we need to adjust according to the actual situation.
rename file
Will Rename the gradle file to gradle.kts, you can complete the rename operation through the following command
find . -name "*.gradle" -type f | xargs -I {} mv {} {}.kts
Other common modifications
Access the gradle property in the kotlin rootProject script
allprojects { repositories { maven { name = "Sonatype-Snapshots" setUrl("https://oss.sonatype.org/content/repositories/snapshots") credentials(PasswordCredentials::class.java) { username = property("ossrhUsername").toString() password = property("ossrhPassword").toString() } } google() jcenter() mavenCentral() } }
Define task
tasks.register("clean", Delete::class.java) { group = "build" delete(rootProject.buildDir) }
Migrating configuration instances
rootProject kotlin dsl build script template
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { // Define extra attribute val kotlin_version by extra("1.4.32") val android_gradle_build_version by extra("4.1.3") repositories { maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") } maven { setUrl("https://maven.aliyun.com/repository/jcenter") } maven { setUrl("https://maven.aliyun.com/repository/google") } maven { setUrl("https://maven.aliyun.com/repository/public") } google() jcenter() mavenCentral() } dependencies { classpath("com.android.tools.build:gradle:$android_gradle_build_version") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { maven { setUrl("https://maven.aliyun.com/repository/jcenter") } maven { setUrl("https://maven.aliyun.com/repository/google") } maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") } maven { setUrl("https://maven.aliyun.com/repository/public") } // Join the temporary warehouse of the project to facilitate the test maven { name = "ProjectLocal-Snapshots" setUrl(File(rootProject.rootDir, "local-maven-repo${File.separator}snapshots")) } maven { name = "ProjectLocal-Release" setUrl(File(rootProject.rootDir, "local-maven-repo${File.separator}release")) } // Join maven snapshot warehouse and release warehouse maven { name = "Sonatype-Snapshots" setUrl("https://oss.sonatype.org/content/repositories/snapshots") } maven { name = "Sonatype-Staging" setUrl("https://oss.sonatype.org/service/local/staging/deploy/maven2/") credentials(PasswordCredentials::class.java) { username = property("ossrhUsername").toString() password = property("ossrhPassword").toString() } } google() mavenCentral() jcenter() } } tasks.register("clean", Delete::class.java) { group = "build" delete(rootProject.buildDir) }
Module build Gradle module build script template
plugins { id("com.android.library") id("signing") // Equivalent to id("") `maven-publish` kotlin("android") kotlin("android.extensions") // Introducing third-party Gradle plug-ins id("com.github.hanlyjiang.android_maven_pub") version ("0.0.9") apply (false) } android { compileSdkVersion(30) buildToolsVersion("30.0.3") defaultConfig { minSdkVersion(22) targetSdkVersion(30) versionCode(1) versionName("1.0.0") testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner") consumerProguardFiles("consumer-rules.pro") } buildTypes { getByName("release") { minifyEnabled(false) proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility(JavaVersion.VERSION_1_8) targetCompatibility(JavaVersion.VERSION_1_8) } } dependencies { implementation("org.jetbrains:annotations:21.0.1") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") // StringRes annotation implementation("androidx.appcompat:appcompat:1.3.1") // Annotation Library https://developer.android.com/jetpack/androidx/releases/annotation#annotation-1.2.0 implementation("androidx.annotation:annotation:1.2.0") } // Create custom task tasks.create("showGitRepoInfo") { group = "help" doLast { println("${getGitBranch()}/${getGitRevision()}") } } // spread function fun String.execute(): String { val process = Runtime.getRuntime().exec(this) return with(process.inputStream.bufferedReader()) { readText() } } /** * Get git revision with work tree status * * @return */ fun getGitRevision(): String { val rev = "git rev-parse --short HEAD".execute().trim() val stat = "git diff --stat".execute().trim() return if (stat.isEmpty()) { rev } else { "$rev-dirty" } } /** * Get git branch name * * @return */ fun getGitBranch(): String { return "git rev-parse --abbrev-ref HEAD".execute().trim() }
Limitations / deficiencies
It is inconvenient to introduce other independent kotlin dsl scripts into kotlin dsl scripts. There will be the problem of unable to identify related dependent objects. In some cases, you still have to import gradle scripts written in groovy.