13.6.10.2 Kotlin 1.4.20 的新变化

原文链接: https://kotlinlang.org/docs/whatsnew1420.html

13.6.10.2 Kotlin 1.4.20 的新变化

阅读 Kotlin 1.4.20 的发行说明,涵盖新的语言特性、Kotlin Multiplatform、JVM、Native、JS 的更新,以及对 Gradle 和 Maven 构建工具的支持。

发布日期:2020 年 11 月 23 日

Kotlin 1.4.20 提供了若干新的实验性特性,并对现有特性(包括 1.4.0 中新增的特性)进行了修复和改进。

你也可以在这篇博客文章中通过更多示例了解新特性。

提示: 关于 Kotlin 发布周期的信息,请参阅 Kotlin 发布流程。

Kotlin/JVM

Kotlin/JVM 的改进旨在使其跟上现代 Java 版本的特性:

Java 15 目标

现在 Java 15 可以作为 Kotlin/JVM 的目标使用。

invokedynamic 字符串拼接

警告: invokedynamic 字符串拼接是实验性的。它可能随时被移除或更改。需要选择启用(详见下文)。请仅将其用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

Kotlin 1.4.20 可以在面向 JVM 9+ 的目标时把字符串拼接编译为动态调用,从而提升性能。

目前,该特性是实验性的,覆盖以下情况:

  • 运算符形式(a + b)、显式形式(a.plus(b))和引用形式((a::plus)(b))的 String.plus。
  • 内联类和 data 类上的 toString。
  • 字符串模板,但只有一个非常量实参的除外(参见 KT-42457)。

要启用 invokedynamic 字符串拼接,请添加 -Xstring-concat 编译器选项,并使用以下值之一:

Kotlin/JS

Kotlin/JS 一直在快速演进,在 1.4.20 中可以找到许多实验性特性和改进:

Gradle DSL 的变化

Kotlin/JS 的 Gradle DSL 获得了若干更新,简化了项目设置和自定义。这包括 webpack 配置调整、对自动生成的 package.json 文件的修改,以及对传递依赖的更佳控制。

webpack 配置的单一入口

浏览器目标新增了一个配置块 commonWebpackConfig。在其中,你可以从一个单一入口调整通用设置,而无需为 webpackTask、runTask 和 testTask 重复配置。

要让这三个任务默认启用 CSS 支持,请在项目的 build.gradle(.kts) 中添加以下代码片段:

1
2
3
4
5
6
browser {
    commonWebpackConfig {
        cssSupport.enabled = true
    }
    binaries.executable()
}

进一步了解配置 webpack 打包。

从 Gradle 自定义 package.json

为了更好地控制 Kotlin/JS 的包管理和分发,你现在可以通过 Gradle DSL 向项目文件 package.json 添加属性。

要向 package.json 添加自定义字段,请在编译的 packageJson 块中使用 customField 函数:

1
2
3
4
5
6
7
kotlin {
    js(BOTH) {
        compilations["main"].packageJson {
            customField("hello", mapOf("one" to 1, "two" to 2))
        }
    }
}

进一步了解 package.json 自定义。

选择性的 yarn 依赖解析

警告: 对选择性 yarn 依赖解析的支持是实验性的。它可能随时被移除或更改。请仅将其用于评估目的。我们非常欢迎你在 Youtrack 上提供反馈。

Kotlin 1.4.20 提供了一种配置 Yarn 选择性依赖解析的方式 —— 这是一种覆盖你所依赖包之依赖的机制。

你可以通过 Gradle 中 YarnPlugin 内部的 YarnRootExtension 来使用它。要影响项目中某个包解析出的版本,请使用 resolution 函数,并传入包名选择器(按 Yarn 的规定)以及它应解析到的版本。

1
2
3
4
5
6
rootProject.plugins.withType<YarnPlugin> {
    rootProject.the<YarnRootExtension>().apply {
        resolution("react", "16.0.0")
        resolution("processor/decamelize", "3.0.0")
    }
}

在这里,你所依赖的、需要 react 的_所有_ npm 依赖都会得到版本 16.0.0,而 processor 的依赖 decamelize 会得到版本 3.0.0。

禁用细粒度工作区

警告: 禁用细粒度工作区是实验性的。它可能随时被移除或更改。请仅将其用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

为加快构建速度,Kotlin/JS Gradle 插件只安装特定 Gradle 任务所需的依赖。例如,webpack-dev-server 包只在你执行某个 *Run 任务时才会安装,而在执行 assemble 任务时不会。当你并行运行多个 Gradle 进程时,这种行为可能带来问题。当依赖需求冲突时,两次安装 npm 包可能会导致错误。

为解决这个问题,Kotlin 1.4.20 提供了禁用这些所谓_细粒度工作区_的选项。该特性目前可通过 Gradle 中 YarnPlugin 内部的 YarnRootExtension 使用。要使用它,请在 build.gradle.kts 文件中添加以下代码片段:

1
2
3
rootProject.plugins.withType<YarnPlugin> {
    rootProject.the<YarnRootExtension>().disableGranularWorkspaces()
}

新的向导模板

为了让你在创建项目时有更方便的自定义方式,Kotlin 的项目向导为 Kotlin/JS 应用带来了新模板:

  • Browser Application —— 一个在浏览器中运行的最小 Kotlin/JS Gradle 项目。
  • React Application —— 一个使用相应 kotlin-wrappers 的 React 应用。它提供了启用样式表、导航组件或状态容器集成的选项。
  • Node.js Application —— 一个在 Node.js 运行时中运行的最小项目。它提供了直接包含实验性 kotlinx-nodejs 包的选项。

使用 IR 编译器忽略编译错误

警告:_忽略编译错误_模式是实验性的。它可能随时被移除或更改。需要选择启用(详见下文)。请仅将其用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

Kotlin/JS 的 IR 编译器带来了一个新的实验性模式 —— 带错误的编译。在该模式下,即使代码包含错误你也能运行它,例如当整个应用还没准备好、但你想先尝试某些东西时。

该模式有两种容错策略:

  • SEMANTIC:编译器会接受语法正确但在语义上不合理的代码,例如 val x: String = 3。

  • SYNTAX:编译器会接受任何代码,即使其中包含语法错误。

要允许带错误编译,请添加 -Xerror-tolerance-policy= 编译器选项,并传入上面列出的值之一。

进一步了解 Kotlin/JS IR 编译器。

Kotlin/Native

Kotlin/Native 在 1.4.20 中的重点是性能和打磨现有特性。以下是值得注意的改进:

逃逸分析

警告: 逃逸分析机制是实验性的。它可能随时被移除或更改。请仅将其用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

Kotlin/Native 获得了新的逃逸分析机制的原型。它通过在栈上而不是堆上分配某些对象来提升运行时性能。在我们的基准测试中,该机制平均带来 10% 的性能提升,我们会继续改进它以进一步加速程序。

逃逸分析在 release 构建(使用 -opt 编译器选项)中作为一个单独的编译阶段运行。

如果你想禁用逃逸分析阶段,请使用 -Xdisable-phases=EscapeAnalysis 编译器选项。

性能改进与缺陷修复

Kotlin/Native 在多个组件中获得了性能改进和缺陷修复,包括 1.4.0 中新增的组件,例如代码共享机制。

选择启用包装 Objective-C 异常

警告: Objective-C 异常包装机制是实验性的。它可能随时被移除或更改。需要选择启用(详见下文)。请仅将其用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

Kotlin/Native 现在可以在运行时处理从 Objective-C 代码抛出的异常,以避免程序崩溃。

你可以选择启用把 NSException 包装为 ForeignException 类型的 Kotlin 异常。它们持有对原始 NSException 的引用。这让你可以获取根本原因的相关信息并正确处理它。

要启用 Objective-C 异常包装,请在 cinterop 调用中指定 -Xforeign-exception-mode objc-wrap 选项,或向 .def 文件添加 foreignExceptionMode = objc-wrap 属性。如果你使用 CocoaPods 集成,请在依赖的 pod {} 构建脚本块中指定该选项,如下所示:

1
2
3
pod("foo") {
    extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
}

默认行为保持不变:当 Objective-C 代码抛出异常时,程序会终止。

CocoaPods 插件的改进

Kotlin 1.4.20 继续为 CocoaPods 集成带来一系列改进。具体来说,你可以试用以下新特性:

改进的任务执行

CocoaPods 插件的任务执行流程得到了改进。例如,如果你新增一个 CocoaPods 依赖,已有依赖不会被重新构建。添加额外的目标也不会影响为已有目标重新构建依赖。

扩展的 DSL

向 Kotlin 项目添加 CocoaPods 依赖的 DSL 获得了新的能力。

除了本地 Pod 和来自 CocoaPods 仓库的 Pod,你还可以添加对以下类型库的依赖:

  • 来自自定义 spec 仓库的库。
  • 来自 Git 仓库的远程库。
  • 来自压缩包的库(也可以通过任意 HTTP 地址获取)。
  • 静态库。
  • 带自定义 cinterop 选项的库。

进一步了解在 Kotlin 项目中添加 CocoaPods 依赖。示例请参阅使用 CocoaPods 的 Kotlin 示例。

更新后的 Xcode 集成

为了与 Xcode 正确配合,Kotlin 需要对 Podfile 做一些修改:

  • 如果你的 Kotlin Pod 有任何 Git、HTTP 或 specRepo Pod 依赖,你也应在 Podfile 中指定它。
  • 当你添加来自自定义 spec 的库时,还应把 spec 的位置写在 Podfile 的开头。

现在集成错误在 IDEA 中会有详细的描述。因此如果你的 Podfile 有问题,你会立即知道如何修复。

进一步了解创建 Kotlin pod。

支持 Xcode 12 库

我们添加了对 Xcode 12 提供的库的支持。现在你可以在 Kotlin 代码中使用它们。

Kotlin Multiplatform

更新多平台库发布产物的结构

从 Kotlin 1.4.20 开始,不再有单独的 metadata 发布产物。metadata 产物现在被包含在代表整个库的_根_发布产物中,当把它作为依赖添加到公共源集时,会自动解析为相应的平台特有产物。

进一步了解发布多平台库。

与早期版本的兼容性

这一结构变化破坏了具有分层项目结构的项目之间的兼容性。如果一个多平台项目和它所依赖的库都具有分层项目结构,那么你需要同时把它们更新到 Kotlin 1.4.20 或更高版本。用 Kotlin 1.4.20 发布的库无法在更早版本发布的项目中使用。

不使用分层项目结构的项目和库仍然保持兼容。

标准库

Kotlin 1.4.20 的标准库提供了用于处理文件的新扩展,以及更好的性能。

java.nio.file.Path 的扩展

警告: java.nio.file.Path 的扩展是实验性的。它们可能随时被移除或更改。需要选择启用(详见下文)。请仅将它们用于评估目的。我们非常欢迎你在 YouTrack 上提供反馈。

现在标准库为 java.nio.file.Path 提供了实验性扩展。以符合 Kotlin 习惯的方式使用现代 JVM 文件 API,现在与使用 kotlin.io 包中的 java.io.File 扩展类似。

1
2
3
4
5
6
// 使用 div(/)运算符构造路径
val baseDir = Path("/base")
val subDir = baseDir / "subdirectory"

// 列出目录中的文件
val kotlinFiles: List<Path> = Path("/home/user").listDirectoryEntries("*.kt")

这些扩展位于 kotlin-stdlib-jdk7 模块的 kotlin.io.path 包中。要使用这些扩展,请选择启用实验性注解 @ExperimentalPathApi。

改进 String.replace 函数的性能

String.replace() 的新实现加快了函数执行速度。区分大小写的变体使用基于 indexOf 的手动替换循环,而不区分大小写的变体使用正则表达式匹配。

Kotlin Android Extensions

在 1.4.20 中,Kotlin Android Extensions 插件被弃用,Parcelable 实现生成器移到单独的插件中。

弃用合成视图

_合成视图_在不久前由 Kotlin Android Extensions 插件引入,用于简化与 UI 元素的交互并减少样板代码。现在 Google 提供了实现同样功能的原生机制 —— Android Jetpack 的视图绑定,因此我们弃用合成视图并推荐使用它。

我们从 kotlin-android-extensions 中提取出 Parcelable 实现生成器,并对其余部分(合成视图)启动弃用周期。目前它们仍可工作,但会给出弃用警告。将来你需要把项目切换到其他方案。以下指南将帮助你从合成视图迁移到视图绑定。

Parcelable 实现生成器的新插件

Parcelable 实现生成器现在位于新的 kotlin-parcelize 插件中。请应用该插件而不是 kotlin-android-extensions。

kotlin-parcelize 和 kotlin-android-extensions 不能同时应用在同一个模块中。

@Parcelize 注解已移到 kotlinx.parcelize 包中。

在 Android 文档中进一步了解 Parcelable 实现生成器。