使用Kotlin写Gradle

现在Gradle也支持Kotlin了,很多人本来就使用Kotlin开发Android,现在用一种语言同时可以把build脚本的工作也做了,可谓一举两得。

Kotlin DSL


DSL即Domain-Specific Language。
Kotlin与Groovy一样是DSL友好的语言,所以很适合用于Gradle脚本编写。

Kotlin版本的Gradle文件后缀会发生变化, ksKotlin Script的意思:

.gradle > .gradle.kts

接下来我们学习如何将gradle文件改成Kts的写法:

环境


我们以一个既有Gradle项目为例:

  • Android Studio 3.5.3
  • Gradle 6.0.1
  • Kotlin 1.3.61
  • JDK 8

将各个gradle文件后缀名改为gradle.kts,并用kotlin重写其内容

gradle > gradle.kts


settings.gradle > settings.gradle.kts

include(":app")
rootProject.name = "MyApplication"

build.gradle -> build.gradle.kts (root)

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:3.5.3")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task<Delete>("clean") {
    delete(rootProject.buildDir)
}

build.gradle -> build.gradle.kts (module)

plugins {
    id("com.android.application")

    kotlin("android")

    kotlin("android.extensions")
}

android {
    compileSdkVersion(29)
    buildToolsVersion = "29.0.0"
    defaultConfig {
        applicationId = "<ApplicationId>"
        minSdkVersion(23)
        targetSdkVersion(29)
        versionCode = 1
        versionName = "0.1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61")
    implementation("androidx.appcompat:appcompat:1.1.0")
    implementation("androidx.core:core-ktx:1.2.0-rc01")
    implementation("androidx.constraintlayout:constraintlayout:2.0.0-beta2")
    testImplementation("junit:junit:4.12")
    androidTestImplementation("androidx.test.ext:junit:1.1.1")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")
}

sync并等待成功结束


依赖管理


当项目有多个module且都依赖了相同的库时,库的版本升级或者替换等会导致多个gradle.kts文件同时修改。此时可以通过将依赖库的配置在buildSrc中集中管理,减少重复修改的次数:

  1. 在项目根目录创建 buildSrc/ 文件夹,用来存放依赖库的配置。
    以普通文件夹的形式创建 ( New > Directory > buildSrc ),不需要 Add Module
  2. Sync Now
    sync中…成功。buildSrc目录下会生成build.gradle
  3. 创建buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}
repositories {
    jcenter()
}
  1. 创建依赖库配置文件
    创建目录buildSrc/src/main/kotlin/depende/,在目录下创建dependencies/Dep.kt,用对象类定义全局静态常量,在其他gradle.kts中可以像调用ext一样调用到这些kt中的静态常量。
object Dep {
    object Plugin {
        val android = "com.android.tools.build:gradle:3.5.3"
        val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Kotlin.version}"
        val safeArgs = "androidx.navigation:navigation-safe-args-gradle-plugin:${AndroidX.Navigation.version}"
    }

    object Test {
        val junit = "junit:junit:4.12"
        val androidJunit = "androidx.test.ext:junit:1.1.1"
        val espressoCore = "androidx.test.espresso:espresso-core:3.2.0"
    }

    object Kotlin {
        const val version = "1.3.61"
        val stdlibJdk = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$version"
    }

    object AndroidX {
        val appCompat = "androidx.appcompat:appcompat:1.1.0"
        val coreKtx = "androidx.core:core-ktx:1.2.0-rc01"
        val constraint = "androidx.constraintlayout:constraintlayout:2.0.0-beta2"
    }
}

定义dependencies/Packages.kt,用来存放Android相关的配置

object Packages {
    const val id = "<Application Id>"
    const val debugIdSuffix = ".debug"

    object SdkVersion {
        const val target = 29
        const val compile = 29
        const val min = 21
    }

    object Version {
        private const val major = 0
        private const val minor = 1
        private const val build = 0

        val code = (major * 100 + minor * 10 + build)
        val name = "$major.$minor.$build"
    }
}

值得一提的是,受益于JVM文件之间可以互相调用的特性,普通的gradle文件也可以调用到kt文件中的Dep或者Packages,实际上groovykt在配置Gradle时是可以共存的,我们这里只介绍在gradle.kts中的写法,.gradle中的写法大家可以自己实践,效果是类似的。

  1. Sync again
    sync中…成功!
  2. 我们在gradle.kts文件中import上述kt文件
import dependencies.Packages
import dependencies.Dep

android {
    compileSdkVersion(Packages.SdkVersion.compile)
    buildToolsVersion = Packages.SdkVersion.compile.toString()
    defaultConfig {
        applicationId = Packages.id
        minSdkVersion(Packages.SdkVersion.min)
        targetSdkVersion(Packages.SdkVersion.target)
        versionCode = Packages.Version.code
        versionName = Packages.Version.name
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation(Dep.Kotlin.stdlibJdk)
    implementation(Dep.AndroidX.appCompat)
    implementation(Dep.AndroidX.coreKtx)
    implementation(Dep.AndroidX.constraint)

    testImplementation(Dep.Test.junit)
    androidTestImplementation(Dep.Test.androidJunit)
    androidTestImplementation(Dep.Test.espressoCore)
}

同样,修改根目录的gradle.kts

import dependencies.Dep

buildscript {
    dependencies {
        classpath(Dep.Plugin.android)
        classpath(Dep.Plugin.kotlin)
    }
}
  1. Sync again
    sync中…成… 出错了?
    https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F308397%2Fbfb225d2-ebb1-2db0-dcb1-6c1ebf532d9d.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=cbc3d7358e52c7b6e169ca8df355728e
org.gradle.internal.exceptions.LocationAwareException: Build file '../build.gradle.kts' line: 10
Script compilation errors:

  Line 10:         classpath(Dep.Plugin.android)
                             ^ Unresolved reference: Dep

  Line 11:         classpath(Dep.Plugin.kotlin)
                             ^ Unresolved reference: Dep

经过一番摸索,下面两种方式中的任一种修改后,可以成功sync

  • 根目录的build.gradle.kts中引用的静态变量的定义放到src/main/kotlin/
  • 将根目录build.gradle.kts改回build.gradle

原因不清楚,有清楚的大佬欢迎留言指教


总结


推荐大家以后改用kotlin配置gradle,至少会带来以下好处:

  • 无需额外学习Groovy
  • 编辑Gradle文件时IDE支持Kotlin智能补全,Groovy则不支持
  • Kotlin提供顶级变量吗,可以通过Dep等全局静态变量传递配置,Groovy则要借助Java的成员变量Project#ext传递配置
  • 错误信息易的读性比Groovy要好得多
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值