kotlin-multiplatform

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kotlin Multiplatform Skill

Kotlin Multiplatform 开发技能

Shared business logic and optional shared UI across Android, iOS, desktop, and web.

在Android、iOS、桌面和Web平台间共享业务逻辑,也可选择共享UI。

Project Structure

项目结构

project/
├── composeApp/                    # Shared Compose UI (if using CMP)
│   └── src/
│       ├── commonMain/            # Shared UI code
│       ├── androidMain/           # Android-specific UI
│       ├── iosMain/               # iOS-specific UI
│       └── desktopMain/          # Desktop-specific UI
├── shared/                        # Shared business logic (KMP)
│   └── src/
│       ├── commonMain/            # Shared code
│       │   └── kotlin/
│       │       ├── data/          # Repositories, data sources
│       │       ├── domain/        # Use cases, models
│       │       └── platform/      # expect declarations
│       ├── androidMain/           # actual implementations
│       ├── iosMain/               # actual implementations
│       └── commonTest/            # Shared tests
├── androidApp/                    # Android entry point
├── iosApp/                        # iOS entry point (Xcode project)
├── build.gradle.kts
└── settings.gradle.kts

project/
├── composeApp/                    # 共享Compose UI(若使用CMP)
│   └── src/
│       ├── commonMain/            # 共享UI代码
│       ├── androidMain/           # Android特定UI代码
│       ├── iosMain/               # iOS特定UI代码
│       └── desktopMain/          # 桌面端特定UI代码
├── shared/                        # 共享业务逻辑(KMP)
│   └── src/
│       ├── commonMain/            # 共享代码
│       │   └── kotlin/
│       │       ├── data/          # 仓库、数据源
│       │       ├── domain/        # 用例、模型
│       │       └── platform/      # expect声明
│       ├── androidMain/           # actual实现
│       ├── iosMain/               # actual实现
│       └── commonTest/            # 共享测试代码
├── androidApp/                    # Android入口
├── iosApp/                        # iOS入口(Xcode项目)
├── build.gradle.kts
└── settings.gradle.kts

expect/actual Pattern

expect/actual 模式

kotlin
// commonMain - expect declaration
expect class PlatformContext

expect fun getPlatformName(): String

expect fun createHttpClient(): HttpClient

// androidMain - actual implementation
actual class PlatformContext(val context: android.content.Context)

actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"

actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) {
    install(ContentNegotiation) { json() }
}

// iosMain - actual implementation
actual class PlatformContext

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

actual fun createHttpClient(): HttpClient = HttpClient(Darwin) {
    install(ContentNegotiation) { json() }
}

kotlin
// commonMain - 期望声明
expect class PlatformContext

expect fun getPlatformName(): String

expect fun createHttpClient(): HttpClient

// androidMain - 实际实现
actual class PlatformContext(val context: android.content.Context)

actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"

actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) {
    install(ContentNegotiation) { json() }
}

// iosMain - 实际实现
actual class PlatformContext

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

actual fun createHttpClient(): HttpClient = HttpClient(Darwin) {
    install(ContentNegotiation) { json() }
}

Key Libraries

核心库

LibraryPurposeMultiplatform?
KtorHTTP clientYes
kotlinx.serializationJSON parsingYes
kotlinx.coroutinesAsync/concurrencyYes
SQLDelightLocal databaseYes
KoinDependency injectionYes
Compose MultiplatformShared UIYes
kotlinx.datetimeDate/timeYes
NapierLoggingYes

用途支持跨平台?
KtorHTTP客户端
kotlinx.serializationJSON解析
kotlinx.coroutines异步/并发处理
SQLDelight本地数据库
Koin依赖注入
Compose Multiplatform共享UI
kotlinx.datetime日期/时间处理
Napier日志记录

Networking with Ktor

基于Ktor的网络请求

kotlin
// commonMain
class ApiClient(private val httpClient: HttpClient) {
    suspend fun getUsers(): List<User> {
        return httpClient.get("https://api.example.com/users").body()
    }

    suspend fun createUser(input: CreateUserInput): User {
        return httpClient.post("https://api.example.com/users") {
            contentType(ContentType.Application.Json)
            setBody(input)
        }.body()
    }
}

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

kotlin
// commonMain
class ApiClient(private val httpClient: HttpClient) {
    suspend fun getUsers(): List<User> {
        return httpClient.get("https://api.example.com/users").body()
    }

    suspend fun createUser(input: CreateUserInput): User {
        return httpClient.post("https://api.example.com/users") {
            contentType(ContentType.Application.Json)
            setBody(input)
        }.body()
    }
}

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

Local Storage with SQLDelight

基于SQLDelight的本地存储

sql
-- src/commonMain/sqldelight/com/example/UserQueries.sq
CREATE TABLE user (
    id TEXT NOT NULL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT NOT NULL,
    cached_at INTEGER NOT NULL
);

selectAll:
SELECT * FROM user ORDER BY name;

insertOrReplace:
INSERT OR REPLACE INTO user (id, name, email, cached_at)
VALUES (?, ?, ?, ?);

deleteById:
DELETE FROM user WHERE id = ?;

sql
-- src/commonMain/sqldelight/com/example/UserQueries.sq
CREATE TABLE user (
    id TEXT NOT NULL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT NOT NULL,
    cached_at INTEGER NOT NULL
);

-- 查询全部:
SELECT * FROM user ORDER BY name;

-- 插入或替换:
INSERT OR REPLACE INTO user (id, name, email, cached_at)
VALUES (?, ?, ?, ?);

-- 根据ID删除:
DELETE FROM user WHERE id = ?;

Compose Multiplatform UI

Compose Multiplatform UI开发

kotlin
// commonMain - Shared composable
@Composable
fun UserListScreen(viewModel: UserListViewModel) {
    val users by viewModel.users.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()

    Scaffold(
        topBar = { TopAppBar(title = { Text("Users") }) }
    ) { padding ->
        if (isLoading) {
            CircularProgressIndicator(modifier = Modifier.padding(padding))
        } else {
            LazyColumn(modifier = Modifier.padding(padding)) {
                items(users) { user ->
                    UserRow(user = user, onClick = { viewModel.onUserClick(user.id) })
                }
            }
        }
    }
}

kotlin
// commonMain - 共享可组合项
@Composable
fun UserListScreen(viewModel: UserListViewModel) {
    val users by viewModel.users.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()

    Scaffold(
        topBar = { TopAppBar(title = { Text("Users") }) }
    ) { padding ->
        if (isLoading) {
            CircularProgressIndicator(modifier = Modifier.padding(padding))
        } else {
            LazyColumn(modifier = Modifier.padding(padding)) {
                items(users) { user ->
                    UserRow(user = user, onClick = { viewModel.onUserClick(user.id) })
                }
            }
        }
    }
}

iOS Integration

iOS 集成

Swift Interop

Swift 互操作

swift
// iosApp - Using shared Kotlin code from Swift
import shared

class UserViewController: UIViewController {
    private let viewModel = UserListViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.users.collect(collector: FlowCollector { users in
            // Update UI with users
        })
    }
}
swift
// iosApp - 在Swift中使用共享Kotlin代码
import shared

class UserViewController: UIViewController {
    private let viewModel = UserListViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.users.collect(collector: FlowCollector { users in
            // 根据用户列表更新UI
        })
    }
}

CocoaPods or SPM Integration

CocoaPods 或 SPM 集成

kotlin
// build.gradle.kts
kotlin {
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    cocoapods {
        summary = "Shared module"
        homepage = "https://example.com"
        ios.deploymentTarget = "16.0"
        framework { baseName = "shared" }
    }
}

kotlin
// build.gradle.kts
kotlin {
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    cocoapods {
        summary = "Shared module"
        homepage = "https://example.com"
        ios.deploymentTarget = "16.0"
        framework { baseName = "shared" }
    }
}

Testing

测试

kotlin
// commonTest
class UserRepositoryTest {
    private val fakeApi = FakeApiClient()
    private val repository = UserRepository(fakeApi)

    @Test
    fun fetchUsersReturnsListFromApi() = runTest {
        fakeApi.setUsers(listOf(User("1", "Alice", "alice@test.com")))

        val users = repository.getUsers()

        assertEquals(1, users.size)
        assertEquals("Alice", users.first().name)
    }
}

kotlin
// commonTest
class UserRepositoryTest {
    private val fakeApi = FakeApiClient()
    private val repository = UserRepository(fakeApi)

    @Test
    fun fetchUsersReturnsListFromApi() = runTest {
        fakeApi.setUsers(listOf(User("1", "Alice", "alice@test.com")))

        val users = repository.getUsers()

        assertEquals(1, users.size)
        assertEquals("Alice", users.first().name)
    }
}

Best Practices

最佳实践

  • Share business logic (networking, storage, models) — keep platform UI native if needed
  • Use
    expect
    /
    actual
    sparingly — prefer interfaces with platform implementations via DI
  • Keep the shared module thin — avoid pulling in platform-heavy dependencies
  • Test shared code in
    commonTest
    — it runs on all targets
  • Use Compose Multiplatform for new projects where native look isn't critical

  • 共享业务逻辑(网络、存储、模型)——若有需求,平台UI可保留原生实现
  • 谨慎使用
    expect
    /
    actual
    ——优先通过依赖注入使用带平台实现的接口
  • 保持共享模块轻量化——避免引入平台相关的重型依赖
  • commonTest
    中测试共享代码——可在所有目标平台运行
  • 若原生界面风格不是核心需求,新项目可使用Compose Multiplatform

Related Resources

相关资源

  • ~/.claude/skills/android-development/SKILL.md
    - Android patterns
  • ~/.claude/skills/ios-development/SKILL.md
    - iOS patterns
  • ~/.claude/agents/flutter-developer.md
    - Alternative cross-platform

Share logic, respect platforms. KMP gives you the best of both worlds.
  • ~/.claude/skills/android-development/SKILL.md
    - Android开发模式
  • ~/.claude/skills/ios-development/SKILL.md
    - iOS开发模式
  • ~/.claude/agents/flutter-developer.md
    - 跨平台开发替代方案

共享逻辑,尊重平台特性。KMP 助你兼顾跨平台与原生体验。