GVKun编程网logo

使用Kotlin DSL 来编写Gradle脚本,替换Groovy(kotlin-gradle-plugin)

47

在这篇文章中,我们将带领您了解使用KotlinDSL来编写Gradle脚本,替换Groovy的全貌,包括kotlin-gradle-plugin的相关情况。同时,我们还将为您介绍有关AndroidGr

在这篇文章中,我们将带领您了解使用Kotlin DSL 来编写Gradle脚本,替换Groovy的全貌,包括kotlin-gradle-plugin的相关情况。同时,我们还将为您介绍有关Android Gradle Kotlin Dsl 中未解决的参考问题、Android Gradle 脚本从 Groovy 迁移到 Kotlin DSL、Android 使用 Kotlin 重写 Gradle 文件(Kotlin Gradle DSL)、Android之使用Kotlin构建Gradle的知识,以帮助您更好地理解这个主题。

本文目录一览:

使用Kotlin DSL 来编写Gradle脚本,替换Groovy(kotlin-gradle-plugin)

使用Kotlin DSL 来编写Gradle脚本,替换Groovy(kotlin-gradle-plugin)

平时我们使用的Gradle文件,使用的语言是Groovy,现在,我们可以使用Kotlin来编写Gradle脚本了,优势如下。

类型KotlinGroovy
自动代码补全支持不支持
是否类型安全不是
源码导航支持不支持
重构自动关联手动修改

接下来让我们新建一个项目,然后配置为kotlin脚本吧。

1.将单引号替换为双引号

在新建的项目中,直接用Android Studio的替换功能,将gradle文件中的将'替换为"

2.修改Gradle文件扩展名

app的build.gradle修改为build.gradle.kts

同步代码,这个时候会报错

3.将groovy语法改为kotlin语法

修改前

plugins {
    id("com.android.application")
    id("kotlin-android")
}

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "com.heiko.mykotlindlstest"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinoptions {
        jvmTarget = "1.8"
    }
}

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation "androidx.core:core-ktx:1.3.1"
    implementation "androidx.appcompat:appcompat:1.2.0"
    implementation "com.google.android.material:material:1.2.1"
    implementation "androidx.constraintlayout:constraintlayout:2.0.1"
    testImplementation "junit:junit:4.+"
    androidTestImplementation "androidx.test.ext:junit:1.1.2"
    androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
}

修改后

plugins {
    id("com.android.application")
    id("kotlin-android")
    //kotlin("android")
    //kotlin("kapt")
}

android {
    compileSdkVersion(30)

    defaultConfig {
        applicationId("com.heiko.mykotlindlstest")
        minSdkVersion(21)
        targetSdkVersion(30)
        versionCode(1)
        versionName("1.0")

        testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner")
    }

    buildTypes {
        named("release") {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinoptions {
        jvmTarget = "1.8"
    }
}

dependencies {
    val kotlin_version = "1.5.10"
    implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
    implementation("androidx.core:core-ktx:1.3.1")
    implementation("androidx.appcompat:appcompat:1.2.0")
    implementation("com.google.android.material:material:1.2.1")
    implementation("androidx.constraintlayout:constraintlayout:2.0.1")
    testImplementation("junit:junit:4.+")
    androidTestImplementation("androidx.test.ext:junit:1.1.2")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
}

接着,我们运行项目,可以发现可以正常运行了。

4.修改其他gradle文件

同理,我们也可以修改其他文件。

修改前的根目录的build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.5.10"
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.1"
        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 {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
    }
}

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

修改后的更目录build.gradle,改名为修改为build.gradle.kts

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    val kotlin_version = "1.5.10"
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.2.1")
        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 {
        google()
        mavenCentral()
        jcenter()
        //maven(url = "https://jitpack.io")
    }
}

tasks {
    val clean by registering(Delete::class) {
        delete(buildDir)
    }
}

修改前的settings.gradle

rootProject.name = "MyKotlinDLSTest"
include ':app'

修改后的settings.gradle,更名为settings.gradle.kts

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

再次运行,可以发现也正常运行 !

其他

感谢 Kotlin Jetpack 实战 | 02. Gradle Kotlin DSL

Android Gradle Kotlin Dsl 中未解决的参考问题

Android Gradle Kotlin Dsl 中未解决的参考问题

如何解决Android Gradle Kotlin Dsl 中未解决的参考问题?

我将我的 gradle 文件从 groovy 迁移到了 kotlin dsl。一切正常,但将值从另一个 kotlin 文件导入 gradle 时存在问题。我可以导入变量并且自动完成工作正常,但是当我构建项目时,它给了我未解析的引用错误。 感谢您的帮助。

Gradle 版本:7.1.1

安卓工作室:北极狐

我在 buildSrc 下创建的 build.gradle.kts :

plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    `kotlin-dsl-precompiled-script-plugins`
}

repositories {
    mavenCentral()
}

我从 buildSrc/src/main/java/Dependencies 导入的文件:

object Versions {
    const val compose_version = "1.0.0"
}

object Dependencies {
    const val compose_ui = "androidx.compose.ui:ui:${Versions.compose_version}"
    const val compose_material = "androidx.compose.material:material:${Versions.compose_version}"
    const val compose_ui_tooling_preview = "androidx.compose.ui:ui-tooling-preview:${Versions.compose_version}"
    const val compose_ui_tooling = "androidx.compose.ui:ui-tooling:${Versions.compose_version}"
    const val compose_ui_test = "androidx.compose.ui:ui-test-junit4:${Versions.compose_version}"
}

app build.gradle.kts 文件:

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

android {
    compileSdk = 30
    defaultConfig {
        applicationId = "com.example.compose"
        minSdk = 21
        targetSdk = 30
        versionCode = 1
        versionName = "1.0"

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

    buildTypes {
        debug {
            isMinifyEnabled = false
            isDebuggable = true
        }
        release {
            isMinifyEnabled = true
            isDebuggable = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro"
            )
        }
    }

    compileOptions {
        sourceCompatibility(JavaVersion.VERSION_1_8)
        targetCompatibility(JavaVersion.VERSION_1_8)
    }
    kotlinoptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    compoSEOptions {
        kotlinCompilerExtensionVersion = "1.0.0"
    }
    packagingOptions {
        resources {
            excludes += "/meta-inf/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {
    implementation("androidx.core:core-ktx:1.6.0")
    implementation("androidx.appcompat:appcompat:1.3.1")
    implementation("com.google.android.material:material:1.4.0")

    // Jetpack Compose
     implementation(Dependencies.compose_ui)
     implementation(Dependencies.compose_material)
     implementation(Dependencies.compose_ui_tooling_preview)
     debugImplementation(Dependencies.compose_ui_tooling)
     androidTestImplementation(Dependencies.compose_ui_test)

    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1")
    implementation("androidx.activity:activity-compose:1.3.0")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}

解决方法

您说您的另一个文件在 buildSrc/src/main/java/Dependencies 下。由于这是一个 Kotlin 文件,它应该是 buildSrc/src/main/kotlin/Dependencies

Android Gradle 脚本从 Groovy 迁移到 Kotlin DSL

Android Gradle 脚本从 Groovy 迁移到 Kotlin DSL

Android Gradle 从 Groovy 迁移到 Kotlin

Android 项目用 Gradle 构建,其脚本语言之前是 Groovy, 目前也提供了 Kotlin 的支持,所以可以迁移到 Kotlin.

官方的迁移文档: Migrating build logic from Groovy to Kotlin 说明的是更通用的步骤.

本文通过一个具体的 Android 项目来举例如何迁移,文后附有 sample.

名词概念解释

  • Gradle: 自动化构建工具。平行产品: Maven.
  • Groovy: 语言,编译后变为 JVM byte code, 兼容 Java 平台.
  • DSL: Domain Specific Language, 领域特定语言.
  • Groovy DSL: Gradle 的 API 是 Java 的,Groovy DSL 是在其之上的脚本语言. Groovy DSL 脚本文件后缀: .gradle.
  • Kotlin DSL: 和前者类似,同样根据 Gradle 的 Java API 构建,只是替换了语言: Groovy -> Kotlin. Kotlin DSL 脚本文件后缀: .gradle.kts.

为什么要迁移

优点:

  • 可以使用 Kotlin, 开发者可能对这个语言更熟悉更喜欢.
  • IDE 支持更好,自动补全提示,重构,imports 等.
  • 类型安全: Kotlin 是静态类型.
  • 不用一次性迁移完:两种语言的脚本可以共存,也可以互相调用.

缺点:

  • 据说 Kotlin DSL 会比 Groovy DSL 稍微慢一点: https://github.com/gradle/kotlin-dsl-samples/issues/902.

迁移步骤

Step 0: 环境支持

Kotlin DSL 在 Android Studio 上是全面支持的。确保使用的 IDE 版本较新.

使用最新版的 Gradle, 这样会包含最新版的 Kotlin DSL.

Step 1: 把单引号替换为双引号

这一步利用 IDE 的文件内搜索替换功能,在想要改的.gradle 文件中,全局替换''" 就行.

比如:

    dependencies {
        classpath ''com.android.tools.build:gradle:3.5.3''
    }

变成了:

    dependencies {
        classpath "com.android.tools.build:gradle:3.5.3"
    }

这一步的改动可见: https://github.com/mengdd/KotlinDSLSample/commit/d3fc644e88fb461920a8b60a0430bb42f6a6053e

Step 2: 区分属性赋值和方法调用

属性赋值用 =, 方法调用用 (). 有时候分不清是属性赋值还是方法调用,可以先用 = 试试,如果报错再改为方法调用.

比如 settings.gradle 在这一步,由:

include ":app"
rootProject.name="KotlinDSLSample"

变成了:

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

第一行是一个方法调用,第二行是一个属性赋值.

项目根目录的 build.gradle 中发生了两处变化,变成了:

    dependencies {
        classpath("com.android.tools.build:gradle:3.5.3")

和:

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

这一步的改动见: https://github.com/mengdd/KotlinDSLSample/commit/b36a508e7d4f1d5d25c23a9772e1cfd9df363fad

Step 3: 文件重命名

上面两步只是准备工作,经过上面两步,你的脚本仍然是 Groovy 的,只不过现在更接近 Kotlin 了.

真正的改变发生在这一步:把后缀为.gradle 的文件重命名,后缀改为.gradle.kts. 没有必要全部改完,这两种脚本是可以共存的.

改完之后各种报错了,不要慌,手动解决一下.

项目根目录的 build.gradle.kts 比较好修,只有全局变量和 task 的问题. app/build.gradle.kts 中要改 plugins, build type 和依赖部分.

不再支持 ext 的全局变量定义.

这里图简单,删掉 ext.kotlin_version = "1.3.61" 这句,直接写:

    dependencies {
        classpath("com.android.tools.build:gradle:3.5.3")
        classpath(kotlin("gradle-plugin", version = "1.3.61"))
    }

task

task 本来是这:

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

现在要改成这样:

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

插件

应用 plugins: 应用插件有 apply 和 plugin 两种方式。强烈建议使用 plugins {} block.

所以 app/build.gradle.kts 里面改成这样:

plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

build type

build type 原先是这样写的:

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

现在改成这样:

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

依赖

libs 文件依赖原先是:

implementation(fileTree(dir: "libs", include: ["*.jar"]))

需要改为:

implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))

另外 kotlin 的部分:

implementation(kotlin("stdlib-jdk7", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION))

这一步的改动见: https://github.com/mengdd/KotlinDSLSample/commit/e392028b128bc83f1d183b880c479687d28cdcc3

自动转换的方法

有一个自动转换的工具: https://github.com/bernaferrari/GradleKotlinConverter

mac 上首先安装 kscript: https://github.com/holgerbrandl/kscript

brew install holgerbrandl/tap/kscript

然后把 gradlekotlinconverter.kts 文件保存到根目录.

再运行:

kscript gradlekotlinconverter.kts build.gradle

kscript gradlekotlinconverter.kts app/build.gradle

进行文件的转换.

我测试了一下转换的结果并不是很完美,还需要手动修改一下.

Toubleshooting

  • 文件后缀改为 kts 之后,app/build.gradleandroid 关键字被标红。我就遇到了这个问题,开始以为没改好,找不到 android 关键字了,各种困惑找原因。但是我发现 build 是可以过的。后来突然 IDE 弹出一个条: There is a new script context available. 点击了 Apply context 就可以了.
  • 要是还有问题,参考一下官方的 android sample 吧: kotlin-dsl-samples/samples/hello-android

参考

  • 我的 Android 项目 sample: KotlinDSLSample
  • 迁移文档: Migrating build logic from Groovy to Kotlin
  • 官方 samples: kotlin-dsl-samples
  • 官方 samples 里面的 android sample: kotlin-dsl-samples/samples/hello-android

原文出处:https://www.cnblogs.com/mengdd/p/android-gradle-migrate-from-groovy-to-kotlin.html

Android 使用 Kotlin 重写 Gradle 文件(Kotlin Gradle DSL)

Android 使用 Kotlin 重写 Gradle 文件(Kotlin Gradle DSL)

概述

众所周知,我们在 Android Studio 是使用 Gradle 来编译的,Gradle 是一种基于 Groovy 语言的构建工具,我们平时看到的 build.gradle 中的语法结构其实就是 Groovy 提供的 DSL 功能

DSL 的全称是领域特定语言(Domain Specific Language),它是编程语言赋予开发者的一种特殊能力,通过它我们可以编写出一些看似脱离其原始语法结构的代码,从而构建出一种专有的语法结构。

毫无疑问,Kotlin 是支持 DSL 的,而且 Gradle 是支持用 Kotlin 语言来编写 Gradle 的构建脚本的,并且 Gradle 官网 也给出了 Groovy 迁移 Kotlin 的指导文章。

image.png

我们来新建一个项目来从 0 将 Gradle 文件改造成由 Kotlin 编写的。

Gradle 脚本改造

一个基于 Gradle 构建的 Android 项目,Gradle 的配置文件一般就只有以下这几种:

  • setting.gradle
  • app/build.gradle
  • project/build.gradle

1623750383(1).jpg

所以我们改造无非就是对这几个文件进行改造。

改造 settings.gradle

这个文件的主要功能就是负责我们项目中 Module 的声明,我们先来看下它原先的代码,如下所示:

include '':app''
rootProject.name = "KotlinGradleDSL"

这段代码很简单,就是声明了 app 这个主 Module,同时定义了我们 project 的名称,我们可以通过 kotlin 的语法进行改写,在改写之前我们先将文件的名字修改成 settings.gradle.kts,改造后的代码如下所示:

include("app")
rootProject.name = "KotlinGradleDSL"
rootProject.buildFileName = "build.gradle.kts"

改造 project/build.gradle

同样我们需要将 build.gradle 的文件名改成 build.gradle.kts,我们先来看下它原先的代码,如下所示:

buildscript {
    ext.kotlin_version = "1.4.31"

    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:4.1.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

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

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

改造后的代码如下所示:

buildscript {

    val gradle_version = "4.1.3"
    val kotlin_version = "1.4.31"

    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath("com.android.tools.build:gradle:$gradle_version")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
    }
}

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

tasks {
    val clean by registering(Delete::class) {
        delete(buildDir)
    }
}

在 Groovy 中,我们有一个 ext 的扩展,但是在 Kotlin 中是没有的,所以我们只能自己先声明一个局部变量,然后通过字符串模板引入,还有就是 classpath 引入的全局依赖,我们是要用大括号括起来,还有一个 clean 的任务,这个也是需要改写的。

接下来,我们来改写一下内容最多的 app/build.gradle。

改造 app/build.gradle

app/build.gradle 里面的内容很多,我们来看每个模块应该怎么改造。

插件的引入改造

Groovy 语法的插件引入如下所示:

plugins {
    id ''com.android.application''
    id ''kotlin-android''
    id ''kotlin-android-extensions''
}

利用 Kotlin 可以改造成下面这样:

plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

SDK 的引入改造

Groovy 语法的 SDK 引入如下所示:

compileSdkVersion 30
buildToolsVersion "30.0.3"

利用 Kotlin 可以改造成下面这样:

compileSdkVersion(30)
buildToolsVersion("30.0.3")

默认配置改造

Groovy 语法的默认配置如下所示:

defaultConfig {
    applicationId "com.example.kotlingradledsl"
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

利用 Kotlin 可以改造成下面这样:

defaultConfig {
    applicationId = "com.example.kotlingradledsl"
    minSdkVersion(23)
    targetSdkVersion(30)
    versionCode = 1
    versionName = "1.0"

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

编译类型改造

Groovy 语法的编译类型如下所示:

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile (''proguard-android-optimize.txt''), ''proguard-rules.pro''
    }
}

利用 Kotlin 可以改造成下面这样:

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

指定 JDK 改造

Groovy 语法的指定 JDK 如下所示:

compileOptions {
    sourceCompatibility JavaVersion . VERSION_1_8
    targetCompatibility JavaVersion . VERSION_1_8
}
kotlinOptions {
    jvmTarget = ''1.8''
}

利用 Kotlin 可以改造成下面这样:

compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = "1.8"
}

依赖的改造

Groovy 语法的依赖如下所示:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.31"
    implementation ''androidx.core:core-ktx:1.2.0''
    implementation ''androidx.appcompat:appcompat:1.1.0''
    implementation ''com.google.android.material:material:1.1.0''
    implementation ''androidx.constraintlayout:constraintlayout:1.1.3''
}

利用 Kotlin 可以改造成下面这样:

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.4.31")
    implementation("androidx.core:core-ktx:1.2.0")
    implementation("androidx.appcompat:appcompat:1.1.0")
    implementation("com.google.android.material:material:1.1.0")
    implementation("androidx.constraintlayout:constraintlayout:1.1.3")
}

完整代码展示

到此为止,我们已经将自动生成 app/build.gradle 里面的内容全部改造完了,我们来看下完整代码,如下所示:

plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

android {
    compileSdkVersion(30)
    buildToolsVersion("30.0.3")

    defaultConfig {
        applicationId = "com.example.kotlingradledsl"
        minSdkVersion(23)
        targetSdkVersion(30)
        versionCode = 1
        versionName = "1.0"

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

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

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

dependencies {

    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.4.31")
    implementation("androidx.core:core-ktx:1.2.0")
    implementation("androidx.appcompat:appcompat:1.1.0")
    implementation("com.google.android.material:material:1.1.0")
    implementation("androidx.constraintlayout:constraintlayout:1.1.3")
}

向 app/build.gradle 加入更高级的特性

上面的 app/build.gradle 里面的内容都是最基本的,我们还需要加入一些更高级的特性,比如自动打包、输出 apk 名称修改等,在上面这个 app/build.gradle 的基础上,我们来开始完善。

自动打包

想要实现自动打包,我们首先要新建一个签名文件,如何实现签名文件这里就不说了,有了签名文件之后,我们就需要在 app/build.gradle 里面进行配置,我们先来看一下 Groovy 语法是如何进行配置的,如下所示:

//签名配置
signingConfigs {
    release {
        // 别名
        keyAlias ''zjgsu''
        //别名密码
        keyPassword ''123456''
        //路径
        storeFile file(''../app/src/main/jks/kotlindsl.jks'')
        //密码
        storePassword ''123456''
    }
}

然后在编译类型中,release 类型里引用即可,如下所示:

signingConfig signingConfigs.release

利用 Kotlin 可以改造成下面这样:

// 签名类型
signingConfigs {
    register("release") {
        // 别名
        keyAlias = "zjgsu"
        // 别名密码
        keyPassword = "123456"
        // 路径
        storeFile = file("src/main/jks/kotlindsl.jks")
        // 签名文件密码
        storePassword = "123456"
    }
}

然后在编译类型中,release 类型里引用即可,如下所示:

signingConfig = signingConfigs.getByName("release")  

配置完签名之后,打包 apk 可以直接用命令打包们也可以直接使用 Android studio 提供的工具打包,如下所示:

image.png

直接双击 assemble 就可以打包 apk 了,打包出来的 apk 如下所示:

image.png

输出类型配置

app-debug 和 app-release 就是我们需要的 apk 了,但是这个名字肯定不是我们需要的,所以我们还需要在 app/build.gradle 中对输出类型进行配置,否则我们每次打包 apk 都得手动改一次名字,太麻烦了,我们先来看一下 Groovy 语法是如何进行配置的,如下所示:

// 输出类型配置
android.applicationVariants.all { variant ->
    def buildType = variant.buildType.name
    def fileName
    variant.outputs.each {
        if (buildType == "release") {
            fileName = "APP_NAMEV-${defaultConfig.versionName}.apk"
        } else if (buildType == "debug") {
            fileName = "APP_NAMEV-${defaultConfig.versionName}_${buildType}.apk"
        }
        it.outputFileName = fileName
    }
}

利用 Kotlin 可以改造成下面这样:

 // 输出类型
android.applicationVariants.all {
    // 编译类型
    val buildType = this.buildType.name
    outputs.all {
        // 判断是否是输出 apk 类型
        if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
            this.outputFileName = "KOTLIN_DSL_V${defaultConfig.versionName}_$buildType.apk"
        }
    }
}

我们再利用 assemble 来打包 apk ,打包出来的 apk 如下所示:

image.png

利用 buildSrc 来统一管理 Gradle 依赖版本

我们在使用 Groovy 语言构建的时候,往往会抽取出一个 build_config.gradle 来作为全局的变量控制,而在 Kotlin 语言中,想要统一管理 Gradle 的依赖版本,则需要使用 buildSrc,有兴趣的可以去看下官网的介绍。

我们来看看如何使用,首先需要在根目录下创建一个 buildSrc 的文件夹,然后创建一系列目录,如下图:

image.png

image.png

目录创建好之后,就需要编写 settings.gradle.kts,如下所示:

rootProject.buildFileName = "build.gradle.kts"

settings.gradle.kts 编写完成后,再来编写 build.gradle.kts,代码如下所示:

apply {
    plugin("kotlin")
}
buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath(kotlin("gradle-plugin", "1.4.31"))
    }
}
dependencies {
    implementation(gradleKotlinDsl())
    implementation(kotlin("stdlib", "1.4.31"))
}
repositories {
    gradlePluginPortal()
}

编译成功之后,我们就可以编写 KotlinConstants.kt 公共类了,具体代码如下所示:

//全局常量
object KotlinConstants {

    //Gradle 版本
    const val gradle_version = "4.1.3"

    //Kotlin 版本
    const val kotlin_version = "1.4.31"
}

//应用配置
object AppConfig {

    //依赖版本
    const val compileSdkVersion = 30

    //编译工具版本
    const val buildToolsVersion = "30.0.3"

    //包名
    const val applicationId = "com.example.kotlingradledsl"

    //最小支持SDK
    const val minSdkVersion = 23

    //当前基于SDK
    const val targetSdkVersion = 30

    //版本编码
    const val versionCode = 1

    //版本名称
    const val versionName = "1.0"
}

//依赖配置
object DependenciesConfig {

    //Kotlin基础库
    const val STD_LIB = "org.jetbrains.kotlin:kotlin-stdlib:${KotlinConstants.kotlin_version}"
}

有了 KotlinConstants.kt 之后,我们就可以在 .gradle 文件中使用了,如 app/build.gradle.kts 代码如下所示:

// 引用插件
plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

// Android 属性
android {
    compileSdkVersion(AppConfig.compileSdkVersion)
    buildToolsVersion(AppConfig.buildToolsVersion)

    defaultConfig {
        applicationId = AppConfig.applicationId
        minSdkVersion(AppConfig.minSdkVersion)
        targetSdkVersion(AppConfig.targetSdkVersion)
        versionCode = AppConfig.versionCode
        versionName = AppConfig.versionName

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

    // 签名类型
    signingConfigs {
        register("release") {
            // 别名
            keyAlias = "zjgsu"
            // 别名密码
            keyPassword = "123456"
            // 路径
            storeFile = file("src/main/jks/kotlindsl.jks")
            // 签名文件密码
            storePassword = "123456"
        }
    }

    // 编译类型
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            // 自动签名打包
            signingConfig = signingConfigs.getByName("release")
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    // 输出类型
    android.applicationVariants.all {
        // 编译类型
        val buildType = this.buildType.name
        outputs.all {
            // 判断是否是输出 apk 类型
            if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
                this.outputFileName = "KOTLIN_DSL_V${defaultConfig.versionName}_$buildType.apk"
            }
        }
    }

    // 指定 JDK
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

dependencies {

    implementation(DependenciesConfig.STD_LIB)
    implementation("androidx.core:core-ktx:1.2.0")
    implementation("androidx.appcompat:appcompat:1.2.0")
    implementation("com.google.android.material:material:1.3.0")
    implementation("androidx.constraintlayout:constraintlayout:2.0.4")
}

至此,Gradle Kotlin DSL 我们已经讲完了。

源码

源码 已上传至 github,有需要的自取。

Android之使用Kotlin构建Gradle

Android之使用Kotlin构建Gradle

Android Studio Gradle
3.4.2 5.1.1

首先kotlin-dsl不是什么新鲜的东西了,Gradle5.0发布的时候就有了
Gradle Kotlin DSL目前的版本是1.0.2

现在是否可以抛弃groovy拥抱kotlin了呢,~~迁移还是有点小麻烦的!

目前在Android Studio中创建项目时,默认情况下使用Groovy创建Gradle脚本,那如何向kotlin-dsl迁移呢?

语法替换

一般情况下,Groovy中使用单引号或者双引号来表达字符串。但是Kotlin必须需要双引号。

对Gradle脚本(以app目录下的build.gralde为例)中的所有单引号执行查找和替换(cmd + R),并将其全部更改为双引号。
然后挨个开始转为kotlin-dsl中的语法

apply plugin: "com.android.application"

apply plugin: "kotlin-android"

apply plugin: "kotlin-android-extensions"

转换之后:(先不用管大量报错)

plugins{
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
}

转换前:

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.1"
    defaultConfig {
        applicationId "com.crucio.test"
        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"
        }
    }
}

改为

android {
    compileSdkVersion (29)
    buildToolsVersion ("29.0.1")
    defaultConfig {
        applicationId = "com.crucio.test"
        minSdkVersion (21)
        targetSdkVersion (29)
        versionCode = 1
        versionName = "1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

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



dependencies {
    val kotlin_version = "1.3.41"
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation ("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version")
    implementation ("androidx.appcompat:appcompat:1.0.2")
    implementation ("androidx.core:core-ktx:1.0.2")
    implementation ("androidx.constraintlayout:constraintlayout:1.1.3")
    testImplementation ("junit:junit:4.12")
    androidTestImplementation ("androidx.test:runner:1.2.0")
    androidTestImplementation ("androidx.test.espresso:espresso-core:3.2.0")
}

这时候我们修改build.gradle文件名称,改为build.gradle.kts
如果语法没有错误会出现如下图所示:

提示:有新的脚本依赖项可用 这时候点击 Enable auto-reload

这时候发现迁移成功了。但是kotlin能不能实现类似于groovy ext依赖呢?buildSrc登场~

buildSrc

自动补全+单击跳转来了,无需在文件之间手动来回切换~
先看下官方对buildSrc介绍

  1. 在项目根目录下新建一个名为buildSrc的文件夹(与项目里的app文件夹同级)。
  2. 在buildSrc文件夹里创建名为build.gradle.kts的文件

plugins{
    `kotlin-dsl`
}

repositories {
     // 必不可少
    jcenter()
}
  1. 在buildSrc文件夹里创建src/main/kotlin文件夹,如下图所示。并在该文件夹下创建kt文件。

写完相关依赖代码后我们再去build.gradle.kts文件中进行替换

看见没? 已经可以自动提示补全了。

buildSrc插件

如果嫌弃手动buildSrc有点麻烦,那插件大法也是有的。

举例一个 buildSrcVersions 自动生成 buildSrc 目录不过插件会生成一个空的 settings.gradle.kts 文件,可以考虑删掉。

补充

关于自定义构建类型
groovy中我们自定义构件类型是这样的

buildTypes {
  release {
    ...
  }
  debug {
    ...
  }
}

但是在kotlin-dsl中buildTypes依赖于NamedDomainObjectContainer

    /**
     * Encapsulates all build type configurations for this project.
     *
     * <p>For more information about the properties you can configure in this block, see {@link
     * BuildType}.
     */
    public void buildTypes(Action<? super NamedDomainObjectContainer<BuildType>> action) {
        checkWritability();
        action.execute(buildTypes);
    }

NamedDomainObjectContainer以及父类NamedDomainObjectCollection有几个用于访问这些字符串键的函数
默认都会有release 与 debug 我们可以用getByName,因为构建容器中默认是有映射的

    /**
     * Locates an object by name, failing if there is no such object. The given configure action is executed against
     * the object before it is returned from this method.
     *
     * @param name The object name
     * @param configureAction The action to use to configure the object.
     * @return The object with the given name, after the configure action has been applied to it. Never returns null.
     * @throws UnknownDomainObjectException when there is no such object in this collection.
     * @since 3.1
     */
    T getByName(String name, Action<? super T> configureAction) throws UnknownDomainObjectException;

如果想要自定义构件类型,getByName会抛异常,我们可以用maybeCreate

/**
     * Looks for an item with the given name, creating and adding it to this container if it does not exist.
     *
     * @param name The name to find or assign to the created object
     * @return The found or created object. Never null.
     */
    T maybeCreate(String name);

结尾

先简单说这么多,

附上根目录的build.gradle.kts


buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath(Libs.com_android_tools_build_gradle)
        classpath(Libs.kotlin_gradle_plugin)
    }
}

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

tasks {
    val clean by registering(Delete::class) {
        delete(buildDir)
    }
}

关于使用Kotlin DSL 来编写Gradle脚本,替换Groovykotlin-gradle-plugin的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Android Gradle Kotlin Dsl 中未解决的参考问题、Android Gradle 脚本从 Groovy 迁移到 Kotlin DSL、Android 使用 Kotlin 重写 Gradle 文件(Kotlin Gradle DSL)、Android之使用Kotlin构建Gradle的相关信息,请在本站寻找。

本文标签: