将构建配置从 Groovy 迁移到 KTS

2024-02-09 06:58
文章标签 配置 构建 迁移 groovy kts

本文主要是介绍将构建配置从 Groovy 迁移到 KTS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

将构建配置从 Groovy 迁移到 KTS

icon.jpg

文章目录

  • 将构建配置从 Groovy 迁移到 KTS
    • 前言
    • Groovy和KTS对比
      • 优点:
      • 缺点和已知问题:
    • Android构建配置从Groovy迁移KTS
      • 准备工作
      • 脚本文件名
      • 一次迁移一个文件
      • 自定义Task
      • 使用 `plugins` 代码块
      • 依赖管理
      • 构建变体
        • 显式和隐式 `buildTypes`
        • 举例说明
      • 访问配置
        • gradle.properties
        • local.properties
        • 获取系统环境变量的值
      • 关于Ext
      • 修改生成apk名称和BuildConfig中添加apk支持的cpu架构
    • buildSrc
    • 参考文档

前言

作为Android开发习惯了面向对象编程,习惯了IDEA提供的各种辅助开发快捷功能。

那么带有陌生的常规语法的Groovy脚本对于我来说一向敬而远之。

Kotlin DSL的出现感觉是为了我们量身定做的,因为采用 Kotlin 编写的代码可读性更高,并且 Kotlin 提供了更好的编译时检查和 IDE 支持。


名词概念解释

  • Gradle: 自动化构建工具. 平行产品: Maven.

  • Groovy: 语言, 编译后变为JVM byte code, 兼容Java平台.

  • DSL: Domain Specific Language, 领域特定语言.

  • Groovy DSL: Gradle的API是Java的,Groovy DSL是在其之上的脚本语言. Groovy DS脚本文件后缀: .gradle.

  • KTS:是指 Kotlin 脚本,这是 Gradle 在构建配置文件中使用的一种 Kotlin 语言形式。Kotlin 脚本是可从命令行运行的 Kotlin 代码。

  • Kotlin DSL:主要是指 Android Gradle 插件 Kotlin DSL,有时也指底层 Gradle Kotlin DSL。

在讨论从 Groovy 迁移时,术语“KTS”和“Kotlin DSL”可以互换使用。换句话说,“将 Android 项目从 Groovy 转换为 KTS”与“将 Android 项目从 Groovy 转换为 Kotlin DSL”实际上是一个意思。

Groovy和KTS对比

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

优点:

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

缺点和已知问题:

  • 目前,采用 KTS 的构建速度可能比采用 Groovy 慢(自测小demo耗时增加约40%(约8s))。

  • Project Structure 编辑器不会展开在 buildSrc 文件夹中定义的用于库名称或版本的常量。

  • KTS 文件目前在项目视图中不提供文本提示。

Android构建配置从Groovy迁移KTS

准备工作

  1. Groovy 字符串可以用单引号 'string' 或双引号 "string" 引用,而 Kotlin 需要双引号 "string"

  2. Groovy 允许在调用函数时省略括号,而 Kotlin 总是需要括号。

  3. Gradle Groovy DSL 允许在分配属性时省略 = 赋值运算符,而 Kotlin 始终需要赋值运算符。

所以在KTS中需要统一做到:

  • 使用双引号统一引号.

groovy-kts-diff1.png

  • 消除函数调用和属性赋值的歧义(分别使用括号和赋值运算符)。

groovy-kts-diff2.png

脚本文件名

Groovy DSL 脚本文件使用 .gradle 文件扩展名。

Kotlin DSL 脚本文件使用 .gradle.kts 文件扩展名。

一次迁移一个文件

由于您可以在项目中结合使用 Groovy build 文件和 KTS build 文件,因此将项目转换为 KTS 的一个简单方法是先选择一个简单的 build 文件(例如 settings.gradle),将其重命名为 settings.gradle.kts,然后将其内容转换为 KTS。之后,确保您的项目在迁移每个 build 文件之后仍然可以编译。

自定义Task

由于Koltin 是静态类型语言,Groovy是动态语言,前者是类型安全的,他们的性质区别很明显的体现在了 task 的创建和配置上。详情可以参考Gradle官方迁移教程

// groovy
task clean(type: Delete) {delete rootProject.buildDir
}
// kotiln-dsl
tasks.register("clean", Delete::class) {delete(rootProject.buildDir)
}
val clean by tasks.creating(Delete::class) {delete(rootProject.buildDir)
}
open class GreetingTask : DefaultTask() {var msg: String? = null@TaskActionfun greet() {println("GreetingTask:$msg")}
}
val msg by tasks.creating(GreetingTask::class) {}
val testTask: Task by tasks.creating {doLast {println("testTask:Run")}
}
val testTask2: Task = task("test2") {doLast { println("Hello, World!") }
}
val testTask3: Task = tasks.create("test3") {doLast {println("testTask:Run")}
}

使用 plugins 代码块

如果您在build 文件中使用 plugins 代码块,IDE 将能够获知相关上下文信息,即使在构建失败时也是如此。IDE 可使用这些信息执行代码补全并提供其他实用建议,从而帮助您解决 KTS 文件中存在的问题。

在您的代码中,将命令式 apply plugin 替换为声明式 plugins 代码块。Groovy 中的以下代码…

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'androidx.navigation.safeargs.kotlin'

在 KTS 中变为以下代码:

plugins {id("com.android.application")id("kotlin-android")id("kotlin-kapt")id("androidx.navigation.safeargs.kotlin")}

如需详细了解 plugins 代码块,请参阅 Gradle 的迁移指南。

注意plugins 代码块仅解析 Gradle 插件门户中提供的插件或使用 pluginManagement 代码块指定的自定义存储库中提供的插件。如果插件来自插件门户中不存在的 buildScript 依赖项,那么这些插件在 Kotlin 中就必须使用 apply 才能应用。例如:

apply(plugin = "kotlin-android")
apply {from("${rootDir.path}/config.gradle")from("${rootDir.path}/version.gradle.kts")
}

如需了解详情,请参阅 Gradle 文档。

强烈建议您plugins {}优先使用块而不是apply()函数。

有两个关键的最佳实践可以更轻松地在 Kotlin DSL 的静态上下文中工作:

  • 使用plugins {}
  • 将本地构建逻辑放在构建的buildSrc目录中

该plugins {}块是关于保持您的构建脚本声明性,以便充分利用Kotlin DSL

使用buildSrc项目是关于将您的构建逻辑组织成共享的本地插件和约定,这些插件和约定易于测试并提供良好的 IDE 支持。

依赖管理

常见依赖

// groovy
implementation project(':library')
implementation 'com.xxxx:xxxx:8.8.1'// kotlin
implementation(project(":library"))
implementation("com.xxxx:xxx:8.8.1")

freeTree

// groovy
implementation fileTree(include: '*.jar', dir: 'libs')//kotlin
implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))

特别类型库依赖

//groovy
implementation(name: 'splibrary', ext: 'aar')//kotlin
implementation (group="",name="splibrary",ext = "aar")

构建变体

显式和隐式 buildTypes

在 Kotlin DSL 中,某些 buildTypes(如 debugrelease,)是隐式提供的。但是,其他 buildTypes 则必须手动创建。

例如,在 Groovy 中,您可能有 debugreleasestaging buildTypes

buildTypesdebug {...}release {...}staging {...}

在 KTS 中,仅 debugrelease buildTypes 是隐式提供的,而 staging 则必须由您手动创建:

buildTypesgetByName("debug") {...}getByName("release") {...}create("staging") {...}
举例说明

Grovvy编写:

productFlavors {demo {dimension "app"}full {dimension "app"multiDexEnabled true}}buildTypes {release {signingConfig signingConfigs.signConfigminifyEnabled truedebuggable falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falsedebuggable true}}
signingConfigs {release {storeFile file("myreleasekey.keystore")storePassword "password"keyAlias "MyReleaseKey"keyPassword "password"}debug {...}}

kotlin-KTL编写:

productFlavors {create("demo") {dimension = "app"}create("full") {dimension = "app"multiDexEnabled = true}
}buildTypes {getByName("release") {signingConfig = signingConfigs.getByName("release")isMinifyEnabled = trueisDebuggable = falseproguardFiles(getDefaultProguardFile("proguard-android.txtt"), "proguard-rules.pro")}getByName("debug") {isMinifyEnabled = falseisDebuggable = true}}signingConfigs {create("release") {storeFile = file("myreleasekey.keystore")storePassword = "password"keyAlias = "MyReleaseKey"keyPassword = "password"}getByName("debug") {...}}

访问配置

gradle.properties

我们通常会把签名信息、版本信息等配置写在gradle.properties中,在kotlin-dsl中我们可以通过一下方式访问:

  1. rootProject.extra.properties
  2. project.extra.properties
  3. rootProject.properties
  4. properties
  5. System.getProperties()

System.getProperties()使用的限制比较多

  • 参数名必须按照systemProp.xxx格式(例如:systemProp.kotlinVersion=1.3.72);
  • 与当前执行的task有关(> Configure project :buildSrc> Configure project :的结果不同,后者无法获取的gradle.properties中的数据);
local.properties

获取工程的local.properties文件

gradleLocalProperties(rootDir)

gradleLocalProperties(projectDir)

获取系统环境变量的值

val JAVA_HOME:String = System.getenv("JAVA_HOME") ?: "default_value"

关于Ext

Google 官方推荐的一个 Gradle 配置最佳实践是在项目最外层 build.gradle 文件的ext代码块中定义项目范围的属性,然后在所有模块间共享这些属性,比如我们通常会这样存放依赖的版本号。

// build.gradleext {compileSdkVersion = 28buildToolsVersion = "28.0.3"supportLibVersion = "28.0.0"...
}

但是由于缺乏IDE的辅助(跳转查看、全局重构等都不支持),实际使用体验欠佳。

KTL中用extra来代替Groovy中的ext

// The extra object can be used for custom properties and makes them available to all
// modules in the project.
// The following are only a few examples of the types of properties you can define.
extra["compileSdkVersion"] = 28
// You can also create properties to specify versions for dependencies.
// Having consistent versions between modules can avoid conflicts with behavior.
extra["supportLibVersion"] = "28.0.0"
android {// Use the following syntax to access properties you defined at the project level:// rootProject.extra["property_name"]compileSdkVersion(rootProject.extra["sdkVersion"])// Alternatively, you can access properties using a type safe delegate:val sdkVersion: Int by rootProject.extra...compileSdkVersion(sdkVersion)
}
...
dependencies {implementation("com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}")...
}

build.gralde中的ext数据是可以在build.gradle.kts中使用extra进行访问的。

修改生成apk名称和BuildConfig中添加apk支持的cpu架构

val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3)
android.applicationVariants.all {val buildType = this.buildType.nameval variant = thisoutputs.all {val name =this.filters.find { it.filterType == com.android.build.api.variant.FilterConfiguration.FilterType.ABI.name }?.identifierval baseAbiCode = abiCodes[name]if (baseAbiCode != null) {//写入cpu架构信息variant.buildConfigField("String", "CUP_ABI", "\"${name}\"")}if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {//修改apk名称if (buildType == "release") {this.outputFileName = "KotlinDSL_${name}_${buildType}.apk"} else if (buildType == "debug") {this.outputFileName = "KotlinDSL_V${variant.versionName}_${name}_${buildType}.apk"}}}
}

buildSrc

我们在使用Groovy语言构建的时候,往往会抽取一个version_config.gradle来作为全局的变量控制,而ext扩展函数则是必须要使用到的,而在我们的Gradle Kotlin DSL中,如果想要使用全局控制,则需要建议使用buildSrc

复杂的构建逻辑通常很适合作为自定义任务或二进制插件进行封装。自定义任务和插件实现不应存在于构建脚本中。buildSrc则不需要在多个独立项目之间共享代码,就可以非常方便地使用该代码了。

buildSrc被视为构建目录。编译器发现目录后,Gradle会自动编译并测试此代码,并将其放入构建脚本的类路径中。

  1. 先创建buildSrc目录;
  2. 在该目录下创建build.gradle.kts文件;
  3. 创建一个buildSrc/src/main/koltin目录;
  4. 在该目录下创建Dependencies.kt文件作为版本管理类;

需要注意的是buildSrcbuild.gradle.kts

plugins {`kotlin-dsl`
}
repositories {jcenter()
}

或者

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

不同版本之间buildSrc下的build.gradle文件执行顺序:

gradle-wrapper.properties:5.6.4

com.android.tools.build:gradle:3.2.0

  1. BuildSrc:build.gradle
  2. setting.gradle
  3. Project:build.gradle
  4. Moudle:build.gradle

gradle-wrapper.properties:6.5

com.android.tools.build:gradle:4.1.1

  1. setting.gradle
  2. BuildSrc:build.gradle
  3. Project:build.gradle
  4. Moudle:build.gradle

所以在非buildSrc目录下的build.gradle.kts文件中我们使用Dependencies.kt需要注意其加载顺序。

参考文档

Android官网-将构建配置从 Groovy 迁移到 KTS

Migrating build logic from Groovy to Kotlin

GitHub:kotlin-dsl-samples

GitHub:kotlin-dsl-samples/samples/hello-android

Kotlin DSL: Gradle scripts in Android made easy

buildSrc官方文档

Gradle’s Kotlin DSL BuildSrc

文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦~!~!

想阅读作者的更多文章,可以查看我 个人博客 和公共号:
振兴书城

这篇关于将构建配置从 Groovy 迁移到 KTS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/693457

相关文章

SpringBoot中HTTP连接池的配置与优化

《SpringBoot中HTTP连接池的配置与优化》这篇文章主要为大家详细介绍了SpringBoot中HTTP连接池的配置与优化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、HTTP连接池的核心价值二、Spring Boot集成方案方案1:Apache HttpCl

Maven 插件配置分层架构深度解析

《Maven插件配置分层架构深度解析》:本文主要介绍Maven插件配置分层架构深度解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Maven 插件配置分层架构深度解析引言:当构建逻辑遇上复杂配置第一章 Maven插件配置的三重境界1.1 插件配置的拓扑

Spring Boot集成Logback终极指南之从基础到高级配置实战指南

《SpringBoot集成Logback终极指南之从基础到高级配置实战指南》Logback是一个可靠、通用且快速的Java日志框架,作为Log4j的继承者,由Log4j创始人设计,:本文主要介绍... 目录一、Logback简介与Spring Boot集成基础1.1 Logback是什么?1.2 Sprin

VSCode中配置node.js的实现示例

《VSCode中配置node.js的实现示例》本文主要介绍了VSCode中配置node.js的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一.node.js下载安装教程二.配置npm三.配置环境变量四.VSCode配置五.心得一.no

Python+wxPython构建图像编辑器

《Python+wxPython构建图像编辑器》图像编辑应用是学习GUI编程和图像处理的绝佳项目,本教程中,我们将使用wxPython,一个跨平台的PythonGUI工具包,构建一个简单的... 目录引言环境设置创建主窗口加载和显示图像实现绘制工具矩形绘制箭头绘制文字绘制临时绘制处理缩放和旋转缩放旋转保存编

Gradle在国内配置镜像加速的实现步骤

《Gradle在国内配置镜像加速的实现步骤》在国内使用Gradle构建项目时,最大的痛点就是依赖下载贼慢,甚至卡死,下面教你如何配置国内镜像加速Gradle下载依赖,主要是通过改写repositori... 目录引言一、修改 build.gradle 或 settings.gradle 的 reposito

使用easy connect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题

《使用easyconnect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题》:本文主要介绍使用easyconnect之后,maven无法... 目录使用easGWowCy connect之后,maven无法使用,原来需要配置-DJava.net.pr

史上最全nginx详细参数配置

《史上最全nginx详细参数配置》Nginx是一个轻量级高性能的HTTP和反向代理服务器,同时也是一个通用代理服务器(TCP/UDP/IMAP/POP3/SMTP),最初由俄罗斯人IgorSyso... 目录基本命令默认配置搭建站点根据文件类型设置过期时间禁止文件缓存防盗链静态文件压缩指定定错误页面跨域问题

nginx负载均衡及详细配置方法

《nginx负载均衡及详细配置方法》Nginx作为一种高效的Web服务器和反向代理服务器,广泛应用于网站的负载均衡中,:本文主要介绍nginx负载均衡及详细配置,需要的朋友可以参考下... 目录一、 nginx负载均衡策略1.1 基本负载均衡策略1.2 第三方策略1.3 策略对比二、 nginx配置2.1

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮