K2 编译器带来的变化
Kotlin 2.0 起默认启用 K2 编译器:前端完全重写,编译速度显著提升,同时为多平台(KMP)提供了统一的中间表示。对开发者而言最直观的感受是:编译更快、IDE 分析更准、智能补全更可靠。
一、KMP 项目结构
// build.gradle.kts (:shared)
plugins {
kotlin("multiplatform")
kotlin("plugin.compose")
id("org.jetbrains.compose")
}
kotlin {
androidTarget()
jvm("desktop")
iosArm64()
iosSimulatorArm64()
js(IR) { browser() }
wasmJs { browser() }
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
implementation("io.ktor:ktor-client-core:3.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
}
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:3.0.0")
}
iosMain.dependencies {
implementation("io.ktor:ktor-client-darwin:3.0.0")
}
}
}核心思路:业务逻辑、网络、数据层写在 commonMain,平台差异用 expect/actual 声明。
// commonMain
expect class PlatformInfo {
val name: String
val version: String
}
// androidMain
actual class PlatformInfo {
actual val name = "Android"
actual val version = android.os.Build.VERSION.RELEASE
}
// iosMain
actual class PlatformInfo {
actual val name = "iOS"
actual val version = platform.UIKit.UIDevice.currentDevice.systemVersion
}二、共享业务层
// 共享的 repository,所有平台复用
class ArticleRepository(private val client: HttpClient) {
private val cache = mutableMapOf<String, Article>()
suspend fun load(id: String): Article = coroutineScope {
cache[id]?.let { return@coroutineScope it }
val dto: ArticleDto = client.get("https://api.example.com/articles/$id").body()
val article = dto.toDomain()
cache[id] = article
article
}
// 并发加载多个
suspend fun loadAll(ids: List<String>): List<Article> = coroutineScope {
ids.map { async { load(it) } }.awaitAll()
}
}三、Compose Multiplatform UI
// commonMain/ui/ArticleScreen.kt
@Composable
fun ArticleScreen(vm: ArticleViewModel = remember { ArticleViewModel() }) {
val state by vm.state.collectAsState()
MaterialTheme {
Scaffold(topBar = { TopAppBar(title = { Text("文章") }) }) { padding ->
when (val s = state) {
is UiState.Loading -> Box(Modifier.fillMaxSize(), Alignment.Center) {
CircularProgressIndicator()
}
is UiState.Error -> Text("出错了:${s.message}", Modifier.padding(padding))
is UiState.Data -> {
LazyColumn(Modifier.padding(padding)) {
items(s.articles, key = { it.id }) { a ->
ArticleRow(a, onClick = { vm.open(a) })
}
}
}
}
}
}
}
@Composable
private fun ArticleRow(a: Article, onClick: () -> Unit) {
ListItem(
headlineContent = { Text(a.title, maxLines = 2) },
supportingContent = { Text(a.summary, maxLines = 1) },
modifier = Modifier.clickable(onClick = onClick),
)
}同一份 UI 代码可运行在:Android(View 层)、iOS(Skiko 渲染,UIKit 互操作)、桌面(JVM)、Web(Wasm)。
四、Web 端:Kotlin/Wasm 的突破
# 构建 Wasm 产物
./gradlew :composeApp:wasmJsBrowserDistributionKotlin/Wasm 编译到 WebAssembly(GC 提案),配合 Compose 可以把整套 UI 跑在浏览器里,产物比 Kotlin/JS 更小、启动更快。
五、工程实践建议
// 用 sealed interface 表达状态,编译器强制穷尽
sealed interface UiState {
data object Loading : UiState
data class Error(val message: String) : UiState
data class Data(val articles: List<Article>) : UiState
}
// 通用 ViewModel 基类,避免在 commonMain 依赖 AndroidX
abstract class BaseViewModel : ViewModel() {
protected val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
fun handleError(e: Throwable) {
// 统一上报
println("error: ${e.message}")
}
}注意事项:
- iOS 端的并发:Kotlin 的多线程协程在 Native 上有冻结限制,推荐使用新内存管理器(默认启用)并把状态限制在单一线程。
- UI 一致性:Compose 在 iOS 上不是 UIKit 原生组件,需要与设计师确认视觉规范。
- 依赖成熟度:数据库推荐 SQLDelight,DI 推荐 Koin 或 kotlin-inject,优先选择明确支持 KMP 的库。
小结
KMP + Compose Multiplatform 让“一套业务逻辑、多端共享”真正落地,尤其适合内部工具、B 端应用与创业团队。K2 编译器和 Kotlin/Wasm 的成熟,是这套方案从尝鲜走向生产的关键拐点。
评论 0
还没有评论,来说两句吧。