Kotlin Multiplatform Development Help

创建你的 Kotlin 多平台应用

在这里,你将学习如何使用Android Studio创建并运行你的第一个Kotlin多平台应用。

Kotlin多平台技术简化了跨平台项目的开发。
Kotlin多平台应用可以在iOS、Android、macOS、Windows、Linux、Web等多种平台上运行。

Kotlin多平台的主要应用场景之一是在移动平台之间共享代码。
你可以在iOS和Android应用之间共享应用逻辑,仅在需要实现原生UI或使用平台API时编写特定平台的代码。

环境配置

如果你尚未完成,请查看为Kotlin多平台开发配置环境一文。
确保你已经:

  • 安装Android Studio的Kotlin多平台插件

  • 至少启动过一次Xcode并接受使用条款(如果你计划构建iOS应用)。

  • 运行Kdoctor检查配置是否存在问题。

以下说明假设你已经安装了目标平台所需的所有软件。

使用向导创建项目

  1. 打开Kotlin多平台向导

  2. 新建项目标签页,将项目名称改为"GreetingKMP",项目ID改为"com.jetbrains.greeting"。

  3. 确保AndroidiOS选项已选中。

  4. 对于iOS,选择不共享UI选项以保持UI原生。

  5. 点击下载按钮并解压生成的压缩包。

Kotlin多平台向导

检查项目结构

  1. 启动Android Studio。

  2. 在欢迎界面点击打开 ,或在编辑器中选择文件 | 打开

  3. 导航到解压后的项目文件夹,然后点击打开

    Android Studio会检测到该文件夹包含Gradle构建文件,并将其作为新项目打开。

  4. Android Studio的默认视图针对Android开发进行了优化。要查看项目的完整文件结构(更适合多平台开发),将视图从Android切换到项目

    选择项目视图

每个Kotlin多平台项目包含三个模块:

  • shared 是一个Kotlin模块,包含Android和iOS应用共有的逻辑——你在平台间共享的代码。它使用Gradle作为构建系统来帮助自动化构建过程。

  • composeApp 是一个构建为Android应用的Kotlin模块。它使用Gradle作为构建系统。
    composeApp模块依赖并使用shared模块作为常规Android库。

  • iosApp 是一个构建为iOS应用的Xcode项目。它依赖并使用shared模块作为iOS框架。
    shared模块可以作为常规框架或CocoaPods依赖使用。
    默认情况下,Kotlin多平台向导创建的项目使用常规框架依赖。

基础多平台项目结构

shared模块由三个源集组成: androidMaincommonMainiosMain 。_源集_是Gradle的一个概念,指逻辑上组合在一起的一组文件,每个组有自己的依赖关系。
在Kotlin多平台中,shared模块中的不同源集可以针对不同平台。

common源集包含共享的Kotlin代码,平台源集使用针对每个目标的特定Kotlin代码。
androidMain使用Kotlin/JVM, iosMain使用Kotlin/Native:

源集和模块结构

当shared模块构建为Android库时,common Kotlin代码被视为Kotlin/JVM。
当它构建为iOS框架时,common Kotlin被视为Kotlin/Native:

Common Kotlin、Kotlin/JVM和Kotlin/Native

编写通用声明

common源集包含可在多个目标平台间共享的代码。
它设计用于包含平台无关的代码。如果你尝试在common源集中使用平台特定的API,IDE会显示警告:

  1. 打开Greeting.kt文件,尝试在greet()函数中访问Java类java.util.Random().nextBoolean()

    import java.util.Random class Greeting { private val platform: Platform = getPlatform() fun greet(): String { val firstWord = if (Random().nextBoolean()) "Hi!" else "Hello!" return firstWord } }

    Android Studio会高亮显示Random类未解析,因为你不能从common Kotlin代码中调用特定的Java函数。

  2. 按照IDE的建议,将其替换为Kotlin标准库中的kotlin.random.Random
    这是一个多平台库,适用于所有平台,并自动包含为依赖项。

  3. Random()中移除括号,因为它是一个抽象类。代码现在应该可以成功编译。

  4. 为问候语添加一些变化。使用Kotlin标准库中的reversed()调用来反转文本:

    import kotlin.random.Random class Greeting { private val platform: Platform = getPlatform() fun greet(): String { val firstWord = if (Random.nextBoolean()) "Hi!" else "Hello!" return "$firstWord Guess what this is! > ${platform.name.reversed()}!" } }

仅在common Kotlin中编写代码有明显的局限性,因为它不能使用任何平台特定的功能。
使用接口和expect/actual机制可以解决这个问题。

查看平台特定实现

common源集可以定义一个接口或预期声明。然后每个平台源集(这里是androidMainiosMain )必须为common源集中的预期声明提供实际的平台特定实现。

在为特定平台生成代码时,Kotlin编译器会合并预期和实际声明,并生成一个带有实际实现的声明。

  1. 当使用Web向导或Android Studio中的Kotlin多平台插件创建项目时,你会得到一个模板,其中commonMain模块包含Platform.kt文件:

    interface Platform { val name: String }

    这是一个包含平台信息的通用Platform接口。

  2. androidMainiosMain模块之间切换。
    你会看到它们为Android和iOS源集提供了相同功能的不同实现:

    // androidMain模块中的Platform.android.kt: class AndroidPlatform: Platform { override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}" }
    // iosMain模块中的Platform.ios.kt: import platform.UIKit.UIDevice class IOSPlatform: Platform { override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion }
    • AndroidPlatform中的name属性实现使用了Android平台代码,即android.os.Build依赖。这段代码是用Kotlin/JVM编写的。如果你在这里尝试访问java.util.Random ,这段代码会编译通过。

    • IOSPlatform中的name属性实现使用了iOS平台代码,即platform.UIKit.UIDevice依赖。它是用Kotlin/Native编写的,意味着你可以用Kotlin编写iOS代码。这段代码成为iOS框架的一部分,稍后你将在iOS应用中从Swift调用它。

  3. 检查不同源集中的getPlatform()函数。它的预期声明没有函数体,实际实现在平台代码中提供:

    // commonMain模块中的Platform.kt: expect fun getPlatform(): Platform
    // androidMain模块中的Platform.android.kt: actual fun getPlatform(): Platform = AndroidPlatform()
    // iosMain模块中的Platform.ios.kt: actual fun getPlatform(): Platform = IOSPlatform()

在这里,common源集定义了一个预期的getPlatform()函数,并在平台源集中提供了实际实现:Android应用的AndroidPlatform()和iOS应用的IOSPlatform()

在为特定平台生成代码时,Kotlin编译器会将预期和实际声明合并为一个带有实际实现的getPlatform()函数。

这就是为什么预期和实际声明应该在同一个包中定义——它们在生成的平台代码中合并为一个声明。
在生成的平台代码中,任何对预期getPlatform()函数的调用都会调用正确的实际实现。

现在你可以运行应用并查看实际效果。

探索expect/actual机制(可选)

模板项目对函数使用了expect/actual机制,但它也适用于大多数Kotlin声明,如属性和类。让我们实现一个预期属性:

  1. 打开commonMain模块中的Platform.kt ,在文件末尾添加:

    expect val num: Int

    Kotlin编译器会提示该属性在平台模块中没有对应的实际声明。

  2. 尝试立即提供实现:

    expect val num: Int = 42

    你会得到一个错误,指出预期声明不能有函数体(这里是初始化器)。
    实现必须在实际平台模块中提供。移除初始化器。

  3. 选中num属性。按下Option + Enter ,选择"添加缺失的实际声明"。
    选择androidMain源集。然后你可以在androidMain/Platform.android.kt中完成实现:

    actual val num: Int = 1
  4. 现在为iosMain模块提供实现。在iosMain/Platform.ios.kt中添加:

    actual val num: Int = 2
  5. num属性添加到greet()函数中以查看差异:

    fun greet(): String { val firstWord = if (Random.nextBoolean()) "Hi!" else "Hello!" return "$firstWord [$num] Guess what this is! > ${platform.name.reversed()}!" }

运行你的应用

你可以从Android Studio为AndroidiOS运行你的多平台应用。

在Android上运行应用

  1. 在运行配置列表中,选择composeApp

  2. 在配置列表旁边选择一个Android虚拟设备,点击运行

    如果列表中没有设备,创建一个新的Android虚拟设备

    在Android上运行多平台应用
    Android上的第一个移动多平台应用

在其他Android模拟设备运行

在真实Android设备运行

在iOS上运行应用

  1. 在单独窗口中启动Xcode。第一次执行此操作时,你可能还需要接受许可条款并允许Xcode执行一些必要的初始任务。

  2. 在Android Studio中,选择运行配置列表中的iosApp ,点击运行

    如果列表中没有可用的iOS配置,添加一个新的运行配置

    在iOS上运行多平台应用
    iOS上的第一个移动多平台应用

在新iOS模拟设备运行

  1. 在运行配置列表点击Edit Configurations

  2. 点击**+选择iOS Application**

  3. 命名配置

  4. 选择.xcodeproj文件

  5. Execution target列表选择模拟设备

  6. 点击Run

在真实iOS设备运行

需先设置与Apple ID关联的Team ID。

设置Team ID

通过KDoctor工具或Xcode设置:

  1. 在终端运行:

    kdoctor --team-ids
  2. iosApp/Configuration/Config.xcconfig中指定Team ID

或通过Xcode:

  1. 打开iosApp/iosApp.xcworkspace

  2. 选择iosApp

  3. 进入Signing & Capabilities

  4. Team列表选择团队

运行应用

连接iPhone后,在Android Studio运行对应的iosApp配置。若设备未注册,需先在Xcode中完成注册流程

下一步

在教程的下一部分,你将学习如何使用平台特定的库更新UI元素。

继续下一部分

另请参阅

获取帮助

23 四月 2025