创建你的 Kotlin 多平台应用
在这里,你将学习如何使用Android Studio创建并运行你的第一个Kotlin多平台应用。
Kotlin多平台技术简化了跨平台项目的开发。
Kotlin多平台应用可以在iOS、Android、macOS、Windows、Linux、Web等多种平台上运行。
Kotlin多平台的主要应用场景之一是在移动平台之间共享代码。
你可以在iOS和Android应用之间共享应用逻辑,仅在需要实现原生UI或使用平台API时编写特定平台的代码。
环境配置
如果你尚未完成,请查看为Kotlin多平台开发配置环境一文。
确保你已经:
安装Android Studio的Kotlin多平台插件。
至少启动过一次Xcode并接受使用条款(如果你计划构建iOS应用)。
运行Kdoctor检查配置是否存在问题。
以下说明假设你已经安装了目标平台所需的所有软件。
使用向导创建项目
打开Kotlin多平台向导。
在新建项目标签页,将项目名称改为"GreetingKMP",项目ID改为"com.jetbrains.greeting"。
确保Android和iOS选项已选中。
对于iOS,选择不共享UI选项以保持UI原生。
点击下载按钮并解压生成的压缩包。

检查项目结构
启动Android Studio。
在欢迎界面点击打开 ,或在编辑器中选择文件 | 打开。
导航到解压后的项目文件夹,然后点击打开。
Android Studio会检测到该文件夹包含Gradle构建文件,并将其作为新项目打开。
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模块由三个源集组成: androidMain
、 commonMain
和iosMain
。_源集_是Gradle的一个概念,指逻辑上组合在一起的一组文件,每个组有自己的依赖关系。
在Kotlin多平台中,shared模块中的不同源集可以针对不同平台。
common源集包含共享的Kotlin代码,平台源集使用针对每个目标的特定Kotlin代码。 androidMain
使用Kotlin/JVM, iosMain
使用Kotlin/Native:

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

编写通用声明
common源集包含可在多个目标平台间共享的代码。
它设计用于包含平台无关的代码。如果你尝试在common源集中使用平台特定的API,IDE会显示警告:
打开
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函数。按照IDE的建议,将其替换为Kotlin标准库中的
kotlin.random.Random
。
这是一个多平台库,适用于所有平台,并自动包含为依赖项。从
Random()
中移除括号,因为它是一个抽象类。代码现在应该可以成功编译。为问候语添加一些变化。使用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源集可以定义一个接口或预期声明。然后每个平台源集(这里是androidMain
和iosMain
)必须为common源集中的预期声明提供实际的平台特定实现。
在为特定平台生成代码时,Kotlin编译器会合并预期和实际声明,并生成一个带有实际实现的声明。
当使用Web向导或Android Studio中的Kotlin多平台插件创建项目时,你会得到一个模板,其中
commonMain
模块包含Platform.kt
文件:interface Platform { val name: String }这是一个包含平台信息的通用
Platform
接口。在
androidMain
和iosMain
模块之间切换。
你会看到它们为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调用它。
检查不同源集中的
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声明,如属性和类。让我们实现一个预期属性:
打开
commonMain
模块中的Platform.kt
,在文件末尾添加:expect val num: IntKotlin编译器会提示该属性在平台模块中没有对应的实际声明。
尝试立即提供实现:
expect val num: Int = 42你会得到一个错误,指出预期声明不能有函数体(这里是初始化器)。
实现必须在实际平台模块中提供。移除初始化器。选中
num
属性。按下Option + Enter ,选择"添加缺失的实际声明"。
选择androidMain
源集。然后你可以在androidMain/Platform.android.kt
中完成实现:actual val num: Int = 1现在为
iosMain
模块提供实现。在iosMain/Platform.ios.kt
中添加:actual val num: Int = 2将
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为Android或iOS运行你的多平台应用。
在Android上运行应用
在运行配置列表中,选择composeApp。
在配置列表旁边选择一个Android虚拟设备,点击运行。
如果列表中没有设备,创建一个新的Android虚拟设备。
在其他Android模拟设备运行
在真实Android设备运行
学习如何配置连接硬件设备并在其上运行应用。
在iOS上运行应用
在单独窗口中启动Xcode。第一次执行此操作时,你可能还需要接受许可条款并允许Xcode执行一些必要的初始任务。
在Android Studio中,选择运行配置列表中的iosApp ,点击运行。
如果列表中没有可用的iOS配置,添加一个新的运行配置。
在新iOS模拟设备运行
在运行配置列表点击Edit Configurations
点击**+选择iOS Application**
命名配置
选择
.xcodeproj
文件在Execution target列表选择模拟设备
点击Run
下一步
在教程的下一部分,你将学习如何使用平台特定的库更新UI元素。
另请参阅
查看如何创建并运行多平台测试以检查代码是否正确工作。
了解更多关于项目结构的信息。
如果你想将现有的Android项目转换为跨平台应用, 完成本教程使你的Android应用跨平台。
获取帮助
Kotlin Slack 。获取邀请并加入#multiplatform频道。
Kotlin问题跟踪器。 报告新问题。