Kotlin多平台KMP實戰:用Compose構建跨平台應用的5個核心模式
编程语言
Kotlin多平台:一套程式碼,全平台執行
iOS用Swift、Android用Kotlin、Web用TypeScript——跨平台開發成本居高不下。Kotlin Multiplatform(KMP)讓你用同一套Kotlin程式碼共享業務邏輯,Compose Multiplatform共享UI,一次編寫即可執行在Android、iOS、Desktop和Web上。2026年,KMP已成為跨平台開發的最優解之一。
本文將從5種核心模式出發,帶你完成expect/actual機制→共享業務邏輯→Compose UI→平台API→生產建置的全鏈路實戰。
核心概念
| 概念 | 說明 |
|---|---|
| KMP | Kotlin Multiplatform Platform,Kotlin跨平台方案 |
| expect/actual | KMP平台差異宣告與實作機制 |
| Compose Multiplatform | 基於Jetpack Compose的跨平台UI框架 |
| 共享邏輯 | 多平台共用的業務邏輯程式碼 |
| 平台特定 | 針對特定平台的實作程式碼 |
| Kotlin/Native | 編譯為原生二進位的Kotlin後端 |
| Kotlin/JS | 編譯為JavaScript的Kotlin後端 |
| 互操作 | 與平台原生程式碼(Swift/JS/C)的互動 |
問題分析:KMP的5大挑戰
- expect/actual理解成本:宣告與實作分離的模式需要適應
- Compose Multiplatform成熟度:iOS端仍在Beta階段
- 平台差異處理:iOS/Android/桌面API差異大
- 除錯體驗差:跨平台除錯鏈路複雜
- 建置配置複雜:Gradle多平台配置學習曲線陡
分步實操:5種KMP實作模式
模式1:KMP專案結構與expect/actual
// commonMain/src/commonMain/kotlin/Platform.kt
expect class Platform() {
val name: String
}
fun getPlatform(): Platform {
return Platform()
}
// androidMain/src/androidMain/kotlin/Platform.kt
actual class Platform actual constructor() {
actual val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
// iosMain/src/iosMain/kotlin/Platform.kt
actual class Platform actual constructor() {
actual val name: String = "iOS ${platform.Foundation.NSProcessInfo.processInfo.operatingSystemVersionString}"
}
模式2:共享業務邏輯層
// commonMain
class GreetingRepository {
private val platform = getPlatform()
fun greet(): String {
return "Hello from ${platform.name}!"
}
}
class UserViewModel {
private val repository = GreetingRepository()
private val _greeting = MutableStateFlow("")
val greeting: StateFlow<String> = _greeting.asStateFlow()
fun loadGreeting() {
_greeting.value = repository.greet()
}
}
模式3:Compose Multiplatform UI
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun App() {
var greeting by remember { mutableStateOf("Loading...") }
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = greeting,
style = MaterialTheme.typography.headlineMedium
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { greeting = GreetingRepository().greet() }) {
Text("Load Greeting")
}
}
}
}
}
}
模式4:平台特定API呼叫
// commonMain
expect class DateTimeFormatter() {
fun format(timestamp: Long): String
}
// androidMain
actual class DateTimeFormatter actual constructor() {
private val sdf = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
actual fun format(timestamp: Long): String = sdf.format(Date(timestamp))
}
// iosMain
actual class DateTimeFormatter actual constructor() {
actual fun format(timestamp: Long): String {
val date = NSDate(timeIntervalSince1970 = timestamp / 1000.0)
val formatter = NSDateFormatter().apply {
dateFormat = "yyyy-MM-dd HH:mm:ss"
}
return formatter.stringFromDate(date)
}
}
模式5:生產建置與發佈
// build.gradle.kts
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
jvm("desktop")
js(IR) {
browser()
}
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
}
androidMain.dependencies {
implementation("androidx.activity:activity-compose:1.9.0")
}
}
}
避坑指南
坑1:commonMain引用平台特定API
// ❌ 錯誤:commonMain直接使用Android API
fun getPath() = android.os.Environment.getDataDirectory().path
// ✅ 正確:透過expect/actual宣告
// commonMain
expect fun getDataPath(): String
// androidMain
actual fun getDataPath() = android.os.Environment.getDataDirectory().path
坑2:Compose iOS記憶體洩漏
// ❌ 錯誤:未釋放iOS原生引用
class IOSBridge {
val delegate = object : NSURLSessionDelegate() { ... }
}
// ✅ 正確:使用WeakReference或手動釋放
class IOSBridge {
private var delegateRef: WeakReference<NSURLSessionDelegate>? = null
fun cleanup() { delegateRef = null }
}
坑3:Kotlin/Native並發限制
// ❌ 錯誤:跨執行緒共享可變狀態
var counter = 0 // 不同執行緒存取會崩潰
// ✅ 正確:使用AtomicReference
val counter = AtomicReference(0)
坑4:Gradle配置過於複雜
// ❌ 錯誤:所有配置寫在一個build.gradle.kts
// 300+行的Gradle檔案
// ✅ 正確:使用convention plugins拆分
// build-logic/convention/src/main/kotlin/KmpConventionPlugin.kt
class KmpConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.kotlin { /* 標準KMP配置 */ }
}
}
坑5:未處理平台字型差異
// ❌ 錯誤:使用平台特定字型名稱
Text(fontFamily = FontFamily("SF Pro"))
// ✅ 正確:使用Compose內建字型或條件判斷
val fontFamily = if (Platform.isIOS) FontFamily("SF Pro") else FontFamily("Roboto")
報錯排查
| 序號 | 報錯資訊 | 原因 | 解決方法 |
|---|---|---|---|
| 1 | Unresolved reference: expect |
未啟用KMP外掛程式 | 新增kotlin("multiplatform")外掛程式 |
| 2 | Actual class has no corresponding expect |
expect/actual不匹配 | 檢查commonMain和平台Main的宣告 |
| 3 | Linker error iOS |
Kotlin/Native與C互操作問題 | 檢查cinterop配置和.def檔案 |
| 4 | Compose compiler error |
Compose版本不相容 | 統一compose外掛程式和compiler版本 |
| 5 | Gradle sync failed |
多平台依賴衝突 | 使用version catalog統一版本 |
| 6 | JS compilation error |
Kotlin/JS不支援反射 | 避免在commonMain使用反射API |
| 7 | iOS build timeout |
Kotlin/Native編譯慢 | 啟用增量編譯和快取 |
| 8 | ClassNotFoundException desktop |
JVM模組未正確配置 | 檢查jvm()目標和mainClass |
| 9 | Module not found |
sourceSets路徑錯誤 | 確認src/commonMain/kotlin目錄結構 |
| 10 | SDK not found |
iOS SDK未安裝 | 安裝Xcode和Command Line Tools |
對比分析
| 維度 | KMP | Flutter | React Native | .NET MAUI |
|---|---|---|---|---|
| 語言 | Kotlin | Dart | JavaScript/TS | C# |
| UI共享 | Compose | Widget | JSX | XAML |
| 原生效能 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| 生態豐富度 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 學習曲線 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 原生互操作 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| iOS成熟度 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
總結:Kotlin Multiplatform憑藉expect/actual機制和Compose Multiplatform,在跨平台開發中提供了獨特的靈活性。KMP適合已有Kotlin/Android生態的團隊,可以漸進式共享程式碼而非全量重寫。2026年Compose Multiplatform iOS端日趨成熟,KMP正成為跨平台開發的務實之選。
線上工具推薦
- JSON格式化:/zh-TW/json/format
- Hash計算:/zh-TW/encode/hash
- cURL轉程式碼:/zh-TW/dev/curl-to-code
本站提供瀏覽器本地工具,免註冊即可試用 →
#Kotlin多平台#KMP#跨平台开发#Compose Multiplatform#2026#编程语言