Skip to content

从 0 到 1 快速上手 KMP

源:Kotlin Multiplatform 官方文档

Kotlin Multiplatform (KMP) 不再是未来,而是当下。它允许您在保持 100% 原生性能的同时,在 Android、iOS、Desktop 和 Web 之间共享核心业务逻辑。

环境准备清单

在开始之前,请确保您的开发机器满足以下要求:

  • JDK: 版本 17 或更高。
  • Android Studio: 推荐 Koala (2024.1.1) 或更高版本,并安装 Kotlin Multiplatform 插件。
  • Xcode: (仅 iOS 开发需要) 建议最新稳定版。
  • Kotlin: 本教程基于 Kotlin 2.3.0

自动化检查工具

推荐运行 kdoctor 工具来诊断环境问题:

bash
brew install kdoctor
kdoctor

创建首个 KMP 项目

最简单的方式是使用官方的 KMP Wizard

  1. 选择目标平台:Android, iOS (Share UI via Compose)iOS (Native UI), Desktop
  2. 输入项目名称和包名。
  3. 下载生成的项目压缩包并解压。
  4. 在 Android Studio 中打开 build.gradle.kts

项目骨架拆解

一个典型的 KMP 项目(以 shared 模块为核心)结构如下:

  • shared/src/commonMain: 核心共享代码(逻辑、数据模型、API 调用)。
  • shared/src/androidMain: Android 特有的 API 实现。
  • shared/src/iosMain: iOS 特有的 API 实现(可直接调用 Apple 框架)。
  • composeApp: (如果选择了 Compose Multiplatform) 共享 UI 代码。

核心配置:build.gradle.kts

shared 模块中,关键配置如下:

kotlin
kotlin {
    // 1. 定义目标平台
    androidTarget()
    
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "SharedFramework"
            isStatic = true
        }
    }

    // 2. 配置源集依赖
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
            implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
        }
        androidMain.dependencies {
            // Android 专用库
        }
        iosMain.dependencies {
            // iOS 专用库
        }
    }
}

跨平台运行

bash
# 在 AS 中直接点击 Run 按钮,或者:
./gradlew :composeApp:installDebug
bash
# 需要在 AS 中配置 iOS 模拟器运行项,
# 或者在 Xcode 中打开 iosApp 目录。
bash
./gradlew :composeApp:run

关键能力详解

本节围绕 shared 模块的关键能力展开,内容遵循 API 核心签名说明 → 标准代码块 → 底层机制说明 的结构,便于直接落地。

源集与 expect/actual 设计

API 核心签名说明

  • expect fun platformName(): String
  • actual fun platformName(): String

标准代码块

kotlin
// commonMain
expect fun platformName(): String

class Greeting {
    fun greeting(): String = "Hello, ${platformName()}!"
}

// androidMain
actual fun platformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"

// iosMain
import platform.UIKit.UIDevice

actual fun platformName(): String = UIDevice.currentDevice.systemName

协程调度与跨平台主线程

API 核心签名说明

  • interface CoroutineScope
  • fun CoroutineScope.launch(block: suspend CoroutineScope.() -> Unit): Job
  • suspend fun <T> withContext(context: CoroutineContext, block: suspend () -> T): T
  • object Dispatchers { val Main: CoroutineDispatcher; val Default: CoroutineDispatcher }

标准代码块

kotlin
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class UserPresenter(
    private val mainDispatcher: CoroutineDispatcher,
    private val ioDispatcher: CoroutineDispatcher,
    private val repo: UserRepository,
) {
    private val scope = CoroutineScope(SupervisorJob() + mainDispatcher)

    fun refresh() {
        scope.launch {
            val user = withContext(ioDispatcher) { repo.fetch() }
            onUserLoaded(user)
        }
    }

    fun clear() {
        scope.cancel()
    }

    private fun onUserLoaded(user: User) { /* 平台层实现 */ }
}

// androidMain
fun createPresenter(repo: UserRepository) = UserPresenter(
    mainDispatcher = Dispatchers.Main.immediate,
    ioDispatcher = Dispatchers.IO,
    repo = repo
)

// iosMain
fun createPresenter(repo: UserRepository) = UserPresenter(
    mainDispatcher = Dispatchers.Main,
    ioDispatcher = Dispatchers.Default,
    repo = repo
)

依赖补充

kotlin
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
        }
        androidMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
        }
    }
}
groovy
kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0"
            }
        }
        androidMain {
            dependencies {
                implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
            }
        }
    }
}
toml
[versions]
kotlinx-coroutines = "1.9.0"

[libraries]
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }

最新稳定版本查看链接:https://github.com/Kotlin/kotlinx.coroutines/releases

序列化与跨平台数据模型

API 核心签名说明

  • @Serializable
  • interface KSerializer<T>
  • fun Json.encodeToString(value: T): String
  • fun Json.decodeFromString(string: String): T

标准代码块

kotlin
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Serializable
data class User(
    val id: String,
    val name: String,
)

private val json = Json {
    ignoreUnknownKeys = true
}

fun encodeUser(user: User): String = json.encodeToString(user)

fun decodeUser(payload: String): User = json.decodeFromString(payload)

依赖补充

kotlin
plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
}

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
        }
    }
}
groovy
plugins {
    id "org.jetbrains.kotlin.multiplatform"
    id "org.jetbrains.kotlin.plugin.serialization"
}

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
            }
        }
    }
}
toml
[versions]
kotlin = "2.3.0"
kotlinx-serialization = "1.7.3"

[libraries]
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }

[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }

最新稳定版本查看链接:https://github.com/Kotlin/kotlinx.serialization/releases

原生框架导出与集成

API 核心签名说明

  • binaries.framework { baseName: String; isStatic: Boolean }
  • freeCompilerArgs += listOf("-Xobjc-generics")

标准代码块

kotlin
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget

kotlin {
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    targets.withType<KotlinNativeTarget>().configureEach {
        binaries.framework {
            baseName = "SharedKit"
            isStatic = true
            freeCompilerArgs += listOf("-Xobjc-generics")
        }
    }
}

跨平台测试与验证

API 核心签名说明

  • @Test
  • kotlin.test.assertEquals(expected: Any?, actual: Any?)
  • kotlin.test.assertTrue(actual: Boolean)
  • kotlin.test.assertFailsWith<T : Throwable>(block: () -> Unit)

标准代码块

kotlin
import kotlin.test.Test
import kotlin.test.assertTrue

class GreetingTest {
    @Test
    fun greetingHasPlatformName() {
        val message = Greeting().greeting()
        assertTrue(message.isNotBlank())
    }
}
kotlin
import kotlin.test.Test
import kotlin.test.assertTrue

class AndroidPlatformTest {
    @Test
    fun platformNameContainsAndroid() {
        val name = platformName()
        assertTrue(name.contains("Android"))
    }
}
kotlin
import kotlin.test.Test
import kotlin.test.assertTrue

class IosPlatformTest {
    @Test
    fun platformNameContainsSystemName() {
        val name = platformName()
        assertTrue(name.isNotBlank())
    }
}

依赖补充

kotlin
kotlin {
    sourceSets {
        commonTest.dependencies {
            implementation(kotlin("test"))
        }
        androidUnitTest.dependencies {
            implementation(kotlin("test-junit"))
        }
    }
}
groovy
kotlin {
    sourceSets {
        commonTest {
            dependencies {
                implementation "org.jetbrains.kotlin:kotlin-test:2.3.0"
            }
        }
        androidUnitTest {
            dependencies {
                implementation "org.jetbrains.kotlin:kotlin-test-junit:2.3.0"
            }
        }
    }
}
toml
[versions]
kotlin = "2.3.0"

[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }

最新稳定版本查看链接:https://github.com/JetBrains/kotlin/releases

常见新手坑位

  • Cocoapods 冲突:

推荐优先使用 Apple Framework 导出模式,除非必须集成大量遗留 Pods。

  • 资源访问: KMP 中访问图片和字符串资源需要使用专门的库(如 Compose Multiplatform Resources)。
  • 编译速度: 首次构建 iOS 框架可能较慢,这是因为 Kotlin/Native 编译器正在进行 LLVM 优化。