Skip to content
Experimental

使用 Swift 导出与 Swift 的互操作性

Kotlin 为 Swift 导出提供实验性支持。它允许您直接导出 Kotlin 源代码,并以符合 Swift 习惯的方式从 Swift 调用 Kotlin 代码,从而无需 Objective-C 头文件。

Swift 导出让 Apple 目标平台的多平台开发更加顺畅。例如,如果您有一个包含顶层函数的 Kotlin 模块,Swift 导出可以实现简洁的模块特定导入,从而移除令人困惑的 Objective-C 下划线和重整名称。

当前的 Swift 导出功能包括:

  • 多模块支持。每个 Kotlin 模块都会被导出为独立的 Swift 模块,简化了函数调用。
  • 软件包支持。在导出过程中会显式保留 Kotlin 软件包,避免在生成的 Swift 代码中出现命名冲突。
  • 类型别名。Kotlin 类型别名会被导出并在 Swift 中保留,从而提高可读性。
  • 增强的基元为 null 性支持。与 Objective-C 互操作不同(后者需要将 Int? 等类型装箱到 KotlinInt 等包装类中以保留为 null 性),Swift 导出会直接转换为 null 性信息。
  • 重载。您可以在 Swift 中无歧义地调用 Kotlin 的重载函数。
  • 扁平化的软件包结构。您可以将 Kotlin 软件包转换为 Swift 枚举,从而从生成的 Swift 代码中移除软件包前缀。
  • 模块名称自定义。您可以在 Kotlin 项目的 Gradle 构建配置中自定义生成的 Swift 模块名称。

启用 Swift 导出

该功能目前处于实验性阶段,尚未准备好用于生产环境。如需试用,请在您的 Kotlin 项目中配置构建文件,并设置 Xcode 以集成 Swift 导出。

配置 Kotlin 项目

您可以在项目中使用以下构建文件作为设置 Swift 导出的起点:

kotlin
// build.gradle.kts
kotlin {

    iosArm64()
    iosSimulatorArm64()

    swiftExport {
        // 设置根模块名称
        moduleName = "Shared"

        // 设置扁平化规则
        // 从生成的 Swift 代码中移除软件包前缀
        flattenPackage = "com.example.sandbox"

        // 配置外部模块导出
        export(project(":subproject")) {
            // 设置导出模块的名称
            moduleName = "Subproject"
            // 设置导出依赖项的扁平化规则
            flattenPackage = "com.subproject.library"
        }

        // 为链接任务提供编译器参数
        configure {
            freeCompilerArgs.add("-Xexpect-actual-classes")
        }
    }
}

Kotlin 编译器会自动生成所有必要的文件(包括 swiftmodule 文件、静态 .a 库、一个头文件和一个 modulemap 文件),并将它们复制到应用的构建目录中,您可以从 Xcode 访问该目录。

您也可以克隆我们已设置好 Swift 导出的公共示例

配置 Xcode 项目

要配置 Xcode 以在项目中集成 Swift 导出,请执行以下操作:

  1. 在 Xcode 中,打开项目设置。

  2. Build Phases 选项卡上,找到包含 embedAndSignAppleFrameworkForXcode 任务的 Run Script 阶段。

  3. 在运行脚本阶段将该脚本替换为 embedSwiftExportForXcode 任务:

    bash
    ./gradlew :<Shared module name>:embedSwiftExportForXcode

    添加 Swift 导出脚本

  4. 构建项目。构建将在输出目录中生成 Swift 模块。

当前限制

Swift 导出目前仅适用于使用直接集成将 iOS 框架连接到 Xcode 项目的项目。这是使用 IntelliJ IDEA 中的 Kotlin Multiplatform 插件或通过 Web 向导创建的 Kotlin Multiplatform 项目的标准配置。

其它已知问题:

  • 当模块在 Gradle 坐标中具有相同名称时(例如 SQLDelight 的 Runtime 模块和 Compose Runtime 模块),Swift 导出将失效 (KT-80185)。

  • 继承自 ListSetMap 的类型在导出期间会被忽略 (KT-80416)。

  • ListSetMap 的继承者无法在 Swift 侧实例化 (KT-80417)。

  • 导出到 Swift 时,Kotlin 泛型类型形参会被类型擦除为其上界。

  • Swift 闭包可以传递到 Kotlin 中,但 Kotlin 无法将函数类型导出到 Swift。

  • 不支持跨语言继承,因此 Swift 类不能直接继承自 Kotlin 导出的类或接口。

  • 目前没有 IDE 迁移提示或自动化工具可用。

  • 使用需要选择性加入 (opt-in) 的声明时,必须在 Gradle 构建文件的“模块级别”添加显式的 optIn 编译器选项。例如,对于 kotlinx.datetime 库:

    kotlin
    swiftExport {
        moduleName = "Shared"
    
        export("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1") {
            moduleName = "KotlinDateTime"
            flattenPackage = "kotlinx.datetime"
        }
    }
    
    // 在模块级别添加单独的 opt-in 块
    compilerOptions {
        optIn.add("kotlin.time.ExperimentalTime")
    }

映射

下表展示了 Kotlin 概念如何映射到 Swift。

KotlinSwift说明
classclass说明
object带有 shared 属性的 class说明
enum classenum说明
typealiastypealias说明
函数函数说明
属性属性说明
构造函数初始值设定项说明
软件包嵌套枚举说明
BooleanBool
CharUnicode.UTF16.CodeUnit
ByteInt8
ShortInt16
IntInt32
LongInt64
UByteUInt8
UShortUInt16
UIntUInt32
ULongUInt64
FloatFloat
DoubleDouble
AnyKotlinBase
UnitVoid
NothingNever说明

声明

类 (Classes)

Swift 导出仅支持直接继承自 Any 的最终类,例如 class Foo()。它们会被翻译为继承自特殊 KotlinBase 类的 Swift 类:

kotlin
// Kotlin
class MyClass {
    val property: Int = 0

    fun method() {}
}
swift
// Swift
public class MyClass : KotlinRuntime.KotlinBase {
    public var property: Swift.Int32 {
        get {
            // ...
        }
    }
    public override init() {
        // ...
    }
    public func method() -> Swift.Void {
        // ...
    }
}

对象 (Objects)

对象会被翻译为具有私有 init 和静态 shared 访问器的 Swift 类:

kotlin
// Kotlin
object O
swift
// Swift
public class O : KotlinRuntime.KotlinBase {
    public static var shared: O {
        get {
            // ...
        }
    }
    private override init() {
        // ...
    }
}

类型别名 (Type aliases)

Kotlin 类型别名会原样导出:

kotlin
// Kotlin
typealias MyInt = Int
swift
// Swift
public typealias MyInt = Swift.Int32

枚举 (Enums)

Kotlin enum class 声明会被导出为常规的原生 Swift enum 类型:

kotlin
// Kotlin
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

val color = Color.RED
swift
// Swift
public enum Color: Swift.CaseIterable, Swift.LosslessStringConvertible, Swift.RawRepresentable {
    case RED, GREEN, BLUE

    public var rgb: Swift.Int32 { get }
}

函数 (Functions)

Swift 导出支持简单的顶层函数和方法:

kotlin
// Kotlin
fun foo(a: Short, b: Bar) {}

fun baz(): Long = 0
swift
// Swift
public func foo(a: Swift.Int16, b: Bar) -> Swift.Void {
    // ...
}

public func baz() -> Swift.Int64 {
    // ...
}

对于 Kotlin 的扩展函数,接收者参数会变成位于第一个位置的普通 Swift 参数:

kotlin
// Kotlin
fun Int.foo(): Unit = TODO()
swift
// Swift
func foo(_ receiver: Int32) {}

带有 vararg 的 Kotlin 函数会被映射到 Swift 的变参函数参数:

kotlin
// Kotlin
fun log(vararg messages: String)
swift
// Swift
public func log(messages: Swift.String...)

目前对带有 suspendinlineoperator 关键字的函数支持有限。 通常不支持泛型类型。

属性 (Properties)

Kotlin 属性会被翻译为 Swift 属性:

kotlin
// Kotlin
val a: Int = 0

var b: Short = 15

const val c: Int = 0
swift
// Swift
public var a: Swift.Int32 {
    get {
        // ...
    }
}
public var b: Swift.Int16 {
    get {
        // ...
    }
    set {
        // ...
    }
}
public var c: Swift.Int32 {
    get {
        // ...
    }
}

构造函数 (Constructors)

构造函数会被翻译为 Swift 初始值设定项:

kotlin
// Kotlin
class Foo(val prop: Int)
swift
// Swift
public class Foo : KotlinRuntime.KotlinBase {
    public init(
        prop: Swift.Int32
    ) {
        // ...
    }
}

类型

kotlin.Nothing

Kotlin 的 Nothing 类型会被翻译为 Never 类型:

kotlin
// Kotlin
fun foo(): Nothing = TODO()

fun baz(input: Nothing) {}
swift
// Swift
public func foo() -> Swift.Never {
    // ...
}

public func baz(input: Swift.Never) -> Void {
    // ...
}

分类器类型 (Classifier types)

Swift 导出目前仅支持直接继承自 Any 的最终类。

软件包 (Packages)

Kotlin 软件包会被翻译为嵌套的 Swift 枚举,以避免名称冲突:

kotlin
// Kotlin
// foo.bar 软件包中的 bar.kt 文件
fun callMeMaybe() {}
kotlin
// Kotlin
// foo.baz 软件包中的 baz.kt 文件
fun callMeMaybe() {}
swift
// Swift
public extension foo.bar {
    public func callMeMaybe() {}
}

public extension foo.baz {
    public func callMeMaybe() {}
}

public enum foo {
    public enum bar {}

    public enum baz {}
}

Swift 导出的演进

我们计划在未来的 Kotlin 版本中扩展并逐步稳定 Swift 导出,改善 Kotlin 与 Swift 之间的互操作性,特别是围绕协程和 flow。

您可以留下您的反馈: