Kotlin Multiplatform 完全指南:从入门到实战(2026)
Kotlin Multiplatform (KMP) 是 2025-2026 年最热门的跨平台技术,它让你共享业务逻辑代码,同时保留各平台的原生 UI 体验。本文从零开始,手把手带你掌握 KMP 的核心概念、项目搭建、网络层、数据持久化,以及最终的多端部署。
一、什么是 Kotlin Multiplatform?
Kotlin Multiplatform (KMP) 是 JetBrains 推出的逻辑跨平台方案:
共享代码 (Kotlin/Common)
├── 网络请求 (Ktor)
├── 数据持久化 (SQLDelight)
├── 业务逻辑 / ViewModel
├── 序列化 (kotlinx.serialization)
└── 工具类 / 扩展函数
↓ ↓ ↓
Android iOS Desktop/Web
(原生 UI) (原生 UI) (Compose MP)
与 Flutter / React Native 的核心区别:
| 对比维度 | KMP | Flutter | React Native |
|---|---|---|---|
| UI 渲染 | 各平台原生 UI | Flutter 自绘 | 原生 UI |
| 性能 | 原生级 | 接近原生 | 依赖 JS Bridge |
| 共享范围 | 业务逻辑 | 全部(UI + 逻辑) | 全部(UI + 逻辑) |
| 学习曲线 | 中(需懂各平台) | 低(一套代码) | 中(需懂各平台) |
| 适用场景 | 已有原生项目想共享逻辑 | 从零开始的全跨平台 | 轻量级跨平台 |
二、环境搭建(2026 最新)
2.1 软件要求
| 工具 | 版本要求 | 说明 |
|---|---|---|
| Android Studio | 2024.1.1+ | 需安装 KMP 插件 |
| Xcode | 15.0+ | iOS 编译依赖 |
| Kotlin | 2.0.0+ | 支持 K2 编译器 |
| Gradle | 8.5+ | 需配合 Kotlin 版本 |
2.2 安装 KMP 插件
打开 Android Studio:
Settings → Plugins → Marketplace
搜索 "Kotlin Multiplatform"
安装并重启
2.3 验证环境
# 检查 Kotlin 版本
kotlin -version
# 检查 Xcode 命令行工具
xcode-select -p
# 应输出:/Applications/Xcode.app/Contents/Developer
# 初始化 KMP 项目(命令行方式)
kotlin multiplatform init
三、创建第一个 KMP 项目
3.1 使用 Android Studio 创建
File → New → New Project
选择 "Kotlin Multiplatform" 模板
填写:
- Project name: "KMPDemo"
- Package name: "com.example.kmpdemo"
- Target platforms: ✅ Android ✅ iOS ✅ Desktop
生成的项目结构:
KMPDemo/
├── composeApp/ # Compose Multiplatform(共享 UI,可选)
│ └── src/
│ ├── androidMain/ # Android 特定代码
│ ├── iosMain/ # iOS 特定代码
│ ├── desktopMain/ # Desktop 特定代码
│ └── commonMain/ # 共享代码 ⭐ 核心
│
├── iosApp/ # iOS 原生项目(Xcode 管理)
│ └── iosApp.xcodeproj
│
├── shared/ # 共享业务逻辑模块 ⭐ 核心
│ └── src/
│ ├── androidMain/ # Android 实际实现
│ ├── iosMain/ # iOS 实际实现(通过 Objective-C 桥接)
│ ├── commonMain/ # 期望声明 + 共享实现
│ └── nativeMain/ # 原生代码(iOS/Android 共用)
│
└── build.gradle.kts # 根构建文件
四、shared 模块详解(核心)
4.1 commonMain:编写共享代码
// shared/src/commonMain/kotlin/AppConfig.kt
object AppConfig {
const val APP_NAME = "KMPDemo"
const val VERSION = "1.0.0"
}
// shared/src/commonMain/kotlin/Platform.kt
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
4.2 androidMain / iosMain:平台特定实现
// shared/src/androidMain/kotlin/Platform.android.kt
actual fun getPlatform(): Platform = object : Platform {
override val name: String
get() = "Android ${android.os.Build.VERSION.SDK_INT}"
}
// shared/src/iosMain/kotlin/Platform.ios.kt
import platform.UIKit.UIDevice
actual fun getPlatform(): Platform = object : Platform {
override val name: String
get() = "iOS ${UIDevice.currentDevice.systemVersion}"
}
4.3 在 Android 中使用共享代码
// androidApp/src/main/kotlin/MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val platform = getPlatform()
println("Running on: ${platform.name}")
// 输出:Running on: Android 35
setContent {
Text("Hello from KMP! Platform: ${platform.name}")
}
}
}
五、网络层实战:Ktor Client
5.1 添加依赖
// shared/build.gradle.kts
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
// Ktor 客户端(跨平台网络库)
implementation("io.ktor:ktor-client-core:3.0.0")
implementation("io.ktor:ktor-client-content-negotiation:3.0.0")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.0")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-android:3.0.0")
implementation("io.ktor:ktor-client-content-negotiation:3.0.0")
}
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-darwin:3.0.0")
}
}
}
}
5.2 封装跨平台 HTTP 客户端
// shared/src/commonMain/kotlin/network/HttpClientFactory.kt
import io.ktor.client.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.serialization.kotlinx.json.*
fun createHttpClient(): HttpClient {
return HttpClient {
// 自动序列化 / 反序列化 JSON
install(ContentNegotiation) {
kotlinx.serialization.json()
}
// 日志(Debug 模式)
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.INFO
}
}
}
5.3 数据模型定义(commonMain)
// shared/src/commonMain/kotlin/model/User.kt
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: Long,
val name: String,
val email: String,
val avatarUrl: String? = null
)
@Serializable
data class ApiResponse<T>(
val code: Int,
val message: String,
val data: T
)
5.4 仓库层(Repository)
// shared/src/commonMain/kotlin/repository/UserRepository.kt
class UserRepository {
private val httpClient = createHttpClient()
private val baseUrl = "https://api.example.com"
suspend fun getUsers(): List<User> {
return try {
httpClient.get("$baseUrl/users")
.body<ApiResponse<List<User>>>()
.data
} catch (e: Exception) {
println("Error fetching users: ${e.message}")
emptyList()
}
}
suspend fun getUserById(id: Long): User? {
return try {
httpClient.get("$baseUrl/users/$id")
.body<ApiResponse<User>>()
.data
} catch (e: Exception) {
null
}
}
}
六、数据持久化:SQLDelight
6.1 添加依赖
// shared/build.gradle.kts
plugins {
id("app.cash.sqldelight") version "2.0.0"
}
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("app.cash.sqldelight:runtime:2.0.0")
implementation("app.cash.sqldelight:coroutines-extensions:2.0.0")
}
}
val androidMain by getting {
dependencies {
implementation("app.cash.sqldelight:android-driver:2.0.0")
}
}
val iosMain by getting {
dependencies {
implementation("app.cash.sqldelight:native-driver:2.0.0")
}
}
}
}
6.2 定义 SQL 模式
-- shared/src/commonMain/sqldelight/com/example/kmpdemo/db/User.sq
CREATE TABLE UserEntity (
id INTEGER NOT NULL,
name TEXT NOT NULL,
email TEXT NOT NULL,
avatarUrl TEXT,
PRIMARY KEY(id)
);
insertUser:
INSERT INTO UserEntity(id, name, email, avatarUrl)
VALUES (?, ?, ?, ?);
getUserById:
SELECT * FROM UserEntity WHERE id = ?;
getAllUsers:
SELECT * FROM UserEntity;
searchUsersByName:
SELECT * FROM UserEntity WHERE name LIKE '%' || ? || '%';
6.3 使用 SQLDelight(commonMain)
// shared/src/commonMain/kotlin/db/DatabaseDriverFactory.kt
expect class DatabaseDriverFactory {
fun createDriver(): SqlDriver
}
// shared/src/commonMain/kotlin/repository/UserLocalRepository.kt
class UserLocalRepository(private val driverFactory: DatabaseDriverFactory) {
private val database = AppDatabase(driverFactory.createDriver())
suspend fun insertUser(user: User) {
database.userQueries.insertUser(
id = user.id,
name = user.name,
email = user.email,
avatarUrl = user.avatarUrl
)
}
suspend fun getAllUsers(): List<UserEntity> {
return database.userQueries.getAllUsers().executeAsList()
}
}
七、在 iOS 项目中使用共享代码
7.1 配置 iOS 框架
// shared/build.gradle.kts
kotlin {
ios {
binaries {
framework {
baseName = "shared"
// 导出需要暴露给 Swift 的类
export("app.cash.sqldelight:runtime:2.0.0")
}
}
}
}
7.2 Swift 中调用共享代码
// iosApp/iosApp/ContentView.swift
import SwiftUI
import shared
struct ContentView: View {
@State private var users: [User] = []
var body: some View {
List(users, id: \.id) { user in
VStack(alignment: .leading) {
Text(user.name).font(.headline)
Text(user.email).font(.subheadline).foregroundColor(.gray)
}
}
.onAppear {
loadUsers()
}
}
func loadUsers() {
let repository = UserRepository()
repository.getUsers(completionHandler: { users, error in
if let users = users {
self.users = users
}
})
}
}
八、KMP + Compose Multiplatform(共享 UI)
⚠️ 注意:Compose Multiplatform 目前(2026 年初)已支持 Android + Desktop,iOS 支持处于 Beta 阶段,生产环境需谨慎。
8.1 添加 Compose Multiplatform 依赖
// composeApp/build.gradle.kts
plugins {
id("org.jetbrains.compose")
id("com.android.application")
}
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
}
}
}
8.2 共享 UI 代码
// composeApp/src/commonMain/kotlin/App.kt
import androidx.compose.material3.*
import androidx.compose.runtime.*
@Composable
fun App() {
MaterialTheme {
var greeting by remember { mutableStateOf("Hello from KMP!") }
val platform = getPlatform()
Scaffold(
topBar = {
TopAppBar(title = { Text("KMP Demo") })
}
) { padding ->
Column(
modifier = Modifier.padding(padding),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(greeting)
Text("Platform: ${platform.name}")
Button(onClick = {
greeting = "You clicked the button!"
}) {
Text("Click me")
}
}
}
}
}
九、实战避坑指南
9.1 iOS 框架编译失败
问题:ld: framework not found shared
解决方案:
1. 在 Xcode 中:Target → Build Settings → Framework Search Paths
添加: $(SRCROOT)/../shared/build/bin/iosArm64/debugFramework
2. 确保每次 Android Studio 编译后,运行:
./gradlew :shared:assembleSharedXCFramework
9.2 泛型在 Swift 中不可见
Kotlin 的泛型在导出到 Swift 时会丢失类型信息。
解决方案:使用 typealias 或接口包装:
// 在 shared 模块中
class UserRepositoryIos : UserRepository() {
// 提供非泛型方法给 Swift 调用
fun getUsersIos(completion: (List<User>) -> Unit) {
// ...
}
}
9.3 SQLDelight 在 iOS 上崩溃
问题:NSInternalInconsistencyException
原因:iOS 上数据库文件路径未正确配置。
解决方案:
// shared/src/iosMain/kotlin/DatabaseDriverFactory.ios.kt
actual class DatabaseDriverFactory {
actual fun createDriver(): SqlDriver {
val documentDirectory = NSFileManager.defaultManager
.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null
)
val dbFilePath = documentDirectory?.path + "/$DB_NAME"
return NativeSqliteDriver(AppDatabase.Schema, dbFilePath)
}
}
十、发布与部署
10.1 Android 打包
# 生成 APK
./gradlew :androidApp:assembleRelease
# 生成 AAB(Google Play 推荐)
./gradlew :androidApp:bundleRelease
10.2 iOS 打包
1. 在 Xcode 中打开 iosApp/iosApp.xcworkspace
2. 选择 Target → Any iOS Device (arm64)
3. Product → Archive
4. 上传到 App Store Connect
十一、KMP 适用场景判断
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 已有 Android + iOS 原生项目,想共享逻辑 | ✅ KMP | 渐进式迁移 |
| 从零开始做跨平台 App | ⚠️ KMP 或 Flutter | 看团队技能栈 |
| 需要高性能游戏 / 图形 | ❌ KMP | 不够适合 |
| 企业级应用(重业务逻辑) | ✅ KMP | 共享业务逻辑优势明显 |
| 初创公司快速验证 MVP | ⚠️ Flutter 更快 | 一套代码跑全平台 |
十二、学习资源
| 资源 | 链接 |
|---|---|
| 官方文档 | kotlinlang.org/docs/multip… |
| Ktor 文档 | ktor.io/docs/ |
| SQLDelight 文档 | cashapp.github.io/sqldelight/ |
| Compose Multiplatform | www.jetbrains.com/lp/compose-… |
| KMP 示例项目 | github.com/Kotlin/kmm-… |
总结
Kotlin Multiplatform 的核心价值是共享业务逻辑,保留原生 UI 体验。2026 年它已趋于成熟,适合:
- Android 开发者想扩展到 iOS,但不想放弃原生 UI
- 企业级应用,业务逻辑复杂,需要跨平台共享
- 渐进式迁移,从共享网络层、数据层开始
下一步学习路径:
KMP 基础 → Ktor 网络层 → SQLDelight 数据持久化
↓
Compose Multiplatform(共享 UI,可选)
↓
发布到 Google Play + App Store
如果本文对你有帮助,欢迎点赞 + 收藏,后续会持续更新 KMP 实战系列文章。