Skip to content

最佳实践清单

基于多个成功的 KMP 项目经验,总结出以下最佳实践,帮助开发者避开常见陷阱,构建高质量的跨平台应用。

架构设计

✅ 分层架构

UI Layer (平台特定)

Presentation Layer (共享 ViewModel 逻辑)

Domain Layer (共享业务逻辑)

Data Layer (共享数据访问)

Platform Layer (平台 API 抽象)

实施要点

  • UI 层使用平台原生技术(SwiftUI, Compose)
  • ViewModel 核心逻辑共享,平台特定部分用 expect/actual
  • 业务逻辑 100% 共享在 commonMain
  • 数据层定义接口,平台层实现

✅ 依赖注入

kotlin
// 使用 Koin 统一管理依赖
val sharedModules = listOf(
    dataModule,     // 数据层
    domainModule,   // 业务层
    networkModule   // 网络层
)

// 平台特定模块
val platformModules = when (platform) {
    Platform.Android -> androidModules
    Platform.iOS -> iosModules
}

startKoin {
    modules(sharedModules + platformModules)
}

代码组织

✅ 最大化代码共享

共享率目标

  • 业务逻辑:90-100%
  • 数据层:80-90%
  • UI 逻辑:50-70%
  • UI 渲染:0-50%(取决于是否使用 Compose Multiplatform)

策略

  1. 优先在 commonMain 实现
  2. 仅在必要时使用 expect/actual
  3. 使用接口 + DI 处理平台差异
  4. UI 复杂时考虑 Compose Multiplatform

✅ 模块化

shared/
├── core/           # 核心工具
├── data/           # 数据层
├── domain/         # 业务层
├── feature-auth/   # 认证功能
├── feature-user/   # 用户功能
└── feature-post/   # 帖子功能

性能优化

✅ 编译时间优化

kotlin
// 1. 使用 Configuration Cache
org.gradle.configuration-cache=true

// 2. 增加堆内存
org.gradle.jvmargs=-Xmx4g

// 3. 并行构建
org.gradle.parallel=true

// 4. 使用 Build Cache
org.gradle.caching=true

✅ 运行时性能

kotlin
// 避免频繁创建对象
class UserRepository {
    private val cache = LruCache<String, User>(100)
    
    suspend fun getUser(id: String): User {
        return cache.get(id) ?: fetchAndCache(id)
    }
}

// 使用协程而非回调
suspend fun loadData(): List<Data> { }  // ✅
fun loadData(callback: (List<Data>) -> Unit) { }  // ❌

✅ iOS Framework 体积优化

kotlin
// build.gradle.kts
kotlin {
    iosTarget.binaries.framework {
        // 启用 bitcode(可选)
        embedBitcode = EmbedBitcodeMode.BITCODE
        
        // 优化编译
        freeCompilerArgs += listOf(
            "-Xoverride-konan-properties=minification.enabled=true"
        )
    }
}

错误处理

✅ 统一错误处理

kotlin
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    data object Loading : Result<Nothing>()
}

// 使用
suspend fun getUser(id: String): Result<User> {
    return try {
        Result.Success(api.fetchUser(id))
    } catch (e: Exception) {
        Result.Error(e)
    }
}

✅ 平台特定错误映射

kotlin
// commonMain
sealed class AppException : Exception() {
    data class Network(override val message: String) : AppException()
    data class NotFound(val id: String) : AppException()
}

// 平台层转换
expect fun Throwable.toAppException(): AppException

// androidMain
actual fun Throwable.toAppException(): AppException {
    return when (this) {
        is IOException -> AppException.Network(message ?: "Network error")
        is HttpException -> when (code()) {
            404 -> AppException.NotFound(message())
            else -> AppException.Network(message())
        }
        else -> AppException.Network("Unknown error")
    }
}

测试策略

✅ 测试金字塔

        UI Tests (5%)

    Integration Tests (15%)

     Unit Tests (80%)

实施

  • 80% 单元测试(commonTest)
  • 15% 集成测试(platform-specific)
  • 5% UI 测试(platform-specific)

✅ 共享测试代码

kotlin
// commonTest
abstract class RepositoryTest {
    abstract fun createRepository(): UserRepository
    
    @Test
    fun testGetUser() = runTest {
        val repository = createRepository()
        val user = repository.getUser("123")
        assertEquals("Alice", user.name)
    }
}

// androidTest
class AndroidRepositoryTest : RepositoryTest() {
    override fun createRepository() = AndroidUserRepository()
}

// iosTest
class IosRepositoryTest : RepositoryTest() {
    override fun createRepository() = IosUserRepository()
}

版本管理

✅ 统一版本号

toml
# gradle/libs.versions.toml
[versions]
app-version = "1.2.0"
app-version-code = "10200"

# 在各平台使用
# Android: versionName, versionCode
# iOS: CFBundleShortVersionString, CFBundleVersion

✅ 依赖版本锁定

kotlin
// 锁定核心依赖版本
kotlin = "2.3.0"          # 精确版本
ktor = "3.0.+"            # 允许修订版更新
compose = "1.7.6"         # 锁定次版本

CI/CD

✅ 自动化流程

yaml
# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  test:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run tests
        run: ./gradlew allTests
      
      - name: Build iOS framework
        run: ./gradlew linkDebugFrameworkIosArm64
      
      - name: Build Android AAR
        run: ./gradlew assembleRelease

文档与协作

✅ 文档规范

  1. README.md - 项目概览、环境配置
  2. docs/architecture.md - 架构设计
  3. docs/api.md - API 文档
  4. CHANGELOG.md - 版本变更记录

✅ 代码规范

kotlin
// KDoc 注释
/**
 * 获取指定用户信息
 * 
 * @param id 用户 ID
 * @return 用户对象,如果不存在则返回 null
 * @throws NetworkException 网络错误
 */
suspend fun getUser(id: String): User?

常见陷阱避开

❌ 避免在 commonMain 依赖平台库

kotlin
// ❌ 错误
// commonMain
import android.util.Log  // 编译错误

// ✅ 正确
// commonMain
expect fun log(message: String)

// androidMain
actual fun log(message: String) {
    android.util.Log.d("App", message)
}

❌ 避免过度使用 expect/actual

kotlin
// ❌ 不必要的 expect/actual
expect fun add(a: Int, b: Int): Int

// ✅ 直接在 commonMain 实现
fun add(a: Int, b: Int): Int = a + b

❌ 避免平台代码泄漏

kotlin
// ❌ 暴露平台类型
fun getUserContext(): android.content.Context

// ✅ 使用抽象
expect class PlatformContext
fun getUserContext(): PlatformContext

清单总结

架构

  • ✅ 使用分层架构
  • ✅ 依赖注入管理依赖
  • ✅ 最大化代码共享

代码质量

  • ✅ 80%+ 单元测试覆盖
  • ✅ 统一错误处理
  • ✅ 代码审查流程

性能

  • ✅ 优化编译时间
  • ✅ 减少 iOS Framework 体积
  • ✅ 使用缓存策略

工程化

  • ✅ CI/CD 自动化
  • ✅ 版本统一管理
  • ✅ 完善文档

遵循这些最佳实践,可以构建高质量、可维护的 Kotlin Multiplatform 应用。