将构建配置从 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

相关文章

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

springboot security之前后端分离配置方式

《springbootsecurity之前后端分离配置方式》:本文主要介绍springbootsecurity之前后端分离配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的... 目录前言自定义配置认证失败自定义处理登录相关接口匿名访问前置文章总结前言spring boot secu

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

springboot简单集成Security配置的教程

《springboot简单集成Security配置的教程》:本文主要介绍springboot简单集成Security配置的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录集成Security安全框架引入依赖编写配置类WebSecurityConfig(自定义资源权限规则

SpringBoot中封装Cors自动配置方式

《SpringBoot中封装Cors自动配置方式》:本文主要介绍SpringBoot中封装Cors自动配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot封装Cors自动配置背景实现步骤1. 创建 GlobalCorsProperties

Spring Boot结成MyBatis-Plus最全配置指南

《SpringBoot结成MyBatis-Plus最全配置指南》本文主要介绍了SpringBoot结成MyBatis-Plus最全配置指南,包括依赖引入、配置数据源、Mapper扫描、基本CRUD操... 目录前言详细操作一.创建项目并引入相关依赖二.配置数据源信息三.编写相关代码查zsRArly询数据库数

一文详解如何从零构建Spring Boot Starter并实现整合

《一文详解如何从零构建SpringBootStarter并实现整合》SpringBoot是一个开源的Java基础框架,用于创建独立、生产级的基于Spring框架的应用程序,:本文主要介绍如何从... 目录一、Spring Boot Starter的核心价值二、Starter项目创建全流程2.1 项目初始化(

SpringBoot配置Ollama实现本地部署DeepSeek

《SpringBoot配置Ollama实现本地部署DeepSeek》本文主要介绍了在本地环境中使用Ollama配置DeepSeek模型,并在IntelliJIDEA中创建一个Sprin... 目录前言详细步骤一、本地配置DeepSeek二、SpringBoot项目调用本地DeepSeek前言随着人工智能技

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子