kotlin-multiplatform

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kotlin Multiplatform: Platform Abstraction Decisions

Kotlin Multiplatform:平台抽象决策

Expert guidance for KMP architecture in Amethyst - deciding what to share vs keep platform-specific.
Amethyst项目中KMP架构的专家指南——决定哪些代码共享、哪些保留平台特定实现。

When to Use This Skill

何时使用此技能

Making platform abstraction decisions:
  • "Should I create expect/actual or keep Android-only?"
  • "Can I share this ViewModel logic?"
  • "Where does this crypto/JSON/network implementation belong?"
  • "This uses Android Context - can it be abstracted?"
  • "Is this code in the wrong module?"
  • Preparing for iOS/web/wasm targets
  • Detecting incorrect placements
在进行平台抽象决策时使用:
  • “我应该创建expect/actual还是仅保留Android专属实现?”
  • “我可以共享这段ViewModel逻辑吗?”
  • “这个加密/JSON/网络实现应该放在哪里?”
  • “这段代码使用了Android Context——可以进行抽象吗?”
  • “这段代码放错模块了吗?”
  • 为iOS/Web/WASM目标平台做准备
  • 检测代码的错误放置

Abstraction Decision Tree

抽象决策树

Central question: "Should this code be reused across platforms?"
Follow this decision path (< 1 minute):
Q: Is it used by 2+ platforms?
├─ NO  → Keep platform-specific
│         Example: Android-only permission handling
└─ YES → Continue ↓

Q: Is it pure Kotlin (no platform APIs)?
├─ YES → commonMain
│         Example: Nostr event parsing, business rules
└─ NO  → Continue ↓

Q: Does it vary by platform or by JVM vs non-JVM?
├─ By platform (Android ≠ iOS ≠ Desktop)
│  → expect/actual
│  Example: Secp256k1Instance (uses different security APIs)
├─ By JVM (Android = Desktop ≠ iOS/web)
│  → jvmAndroid
│  Example: Jackson JSON parsing (JVM library)
└─ Complex/UI-related
   → Keep platform-specific
   Example: Navigation (Activity vs Window too different)

Final check:
Q: Maintenance cost of abstraction < duplication cost?
├─ YES → Proceed with abstraction
└─ NO  → Duplicate (simpler)
核心问题: “这段代码应该跨平台复用吗?”
遵循以下决策路径(耗时<1分钟):
Q: 是否有2个及以上平台需要使用这段代码?
├─ 否  → 保留平台特定实现
│         示例:仅Android的权限处理
└─ 是 → 继续 ↓

Q: 这段代码是纯Kotlin实现(无平台API)吗?
├─ 是 → 放在commonMain
│         示例:Nostr事件解析、业务规则
└─ 否  → 继续 ↓

Q: 实现差异是按平台划分还是按JVM/非JVM划分?
├─ 按平台划分(Android ≠ iOS ≠ 桌面端)
│  → 使用expect/actual
│  示例:Secp256k1Instance(使用不同的安全API)
├─ 按JVM/非JVM划分(Android = 桌面端 ≠ iOS/Web)
│  → 放在jvmAndroid
│  示例:Jackson JSON解析(JVM专属库)
└─ 复杂UI相关
   → 保留平台特定实现
   示例:导航(Activity与Window差异过大)

最终检查:
Q: 抽象的维护成本 < 代码重复的成本?
├─ 是 → 进行抽象
└─ 否  → 重复实现(更简单)

Real Examples from Codebase

代码库中的实际示例

Crypto → expect/actual:
kotlin
// commonMain - expect declaration
expect object Secp256k1Instance {
    fun signSchnorr(data: ByteArray, privKey: ByteArray): ByteArray
}

// androidMain - uses Android Keystore
// jvmMain - uses Desktop JVM crypto
// iosMain - uses iOS Security framework
Why: Each platform has different security APIs.
JSON parsing → jvmAndroid:
kotlin
// quartz/build.gradle.kts
val jvmAndroid = create("jvmAndroid") {
    api(libs.jackson.module.kotlin)
}
Why: Jackson is JVM-only, works on Android + Desktop, not iOS/web.
Navigation → platform-specific:
  • Android:
    MainActivity
    (Activity + Compose Navigation)
  • Desktop:
    Window
    + sidebar + MenuBar Why: UI paradigms fundamentally different.
加密模块 → expect/actual:
kotlin
// commonMain - expect声明
expect object Secp256k1Instance {
    fun signSchnorr(data: ByteArray, privKey: ByteArray): ByteArray
}

// androidMain - 使用Android Keystore
// jvmMain - 使用桌面端JVM加密库
// iosMain - 使用iOS Security框架
原因: 每个平台有不同的安全API。
JSON解析 → jvmAndroid:
kotlin
// quartz/build.gradle.kts
val jvmAndroid = create("jvmAndroid") {
    api(libs.jackson.module.kotlin)
}
原因: Jackson是JVM专属库,可在Android和桌面端运行,但不支持iOS/Web。
导航 → 平台特定实现:
  • Android:
    MainActivity
    (Activity + Compose Navigation)
  • 桌面端:
    Window
    + 侧边栏 + 菜单栏 原因: UI范式存在根本性差异。

Mental Model: Source Sets as Dependency Graph

思维模型:将源码集视为依赖图

Think of source sets as a dependency graph, not folders.
┌─────────────────────────────────────────────┐
│ commonMain = Contract (pure Kotlin)         │
│ - Business logic, protocol, data models     │
│ - No platform APIs                          │
└────────────┬────────────────────────────────┘
             ├──────────────────────┬────────────────────
             │                      │
             ▼                      ▼
   ┌───────────────────┐  ┌──────────────────┐
   │ jvmAndroid        │  │ iosMain          │
   │ JVM libs shared   │  │ iOS common       │
   │ - Jackson         │  │                  │
   │ - OkHttp          │  └────┬─────────────┘
   └───┬───────────┬───┘       │
       │           │            ├─→ iosX64Main
       ▼           ▼            ├─→ iosArm64Main
  ┌─────────┐ ┌──────────┐     └─→ iosSimulatorArm64Main
  │android  │ │jvmMain   │
  │Main     │ │(Desktop) │
  └─────────┘ └──────────┘

Future: jsMain, wasmMain
Key insight: jvmAndroid is NOT a platform - it's a shared JVM layer.
将源码集视为依赖图,而非简单的文件夹。
┌─────────────────────────────────────────────┐
│ commonMain = 契约层(纯Kotlin)         │
│ - 业务逻辑、协议、数据模型     │
│ - 无平台API                          │
└────────────┬────────────────────────────────┘
             ├──────────────────────┬────────────────────
             │                      │
             ▼                      ▼
   ┌───────────────────┐  ┌──────────────────┐
   │ jvmAndroid        │  │ iosMain          │
   │ 共享JVM库   │  │ iOS通用代码       │
   │ - Jackson         │  │                  │
   │ - OkHttp          │  └────┬─────────────┘
   └───┬───────────┬───┘       │
       │           │            ├─→ iosX64Main
       ▼           ▼            ├─→ iosArm64Main
  ┌─────────┐ ┌──────────┐     └─→ iosSimulatorArm64Main
  │android  │ │jvmMain   │
  │Main     │ │(桌面端) │
  └─────────┘ └──────────┘

未来规划: jsMain, wasmMain
关键见解: jvmAndroid不是一个平台,而是一个共享JVM层。

The jvmAndroid Pattern

jvmAndroid模式

Unique to Amethyst. Shares JVM libraries between Android + Desktop.
Amethyst项目专属模式,在Android和桌面端之间共享JVM库。

When to Use jvmAndroid

何时使用jvmAndroid

Use jvmAndroid when:
  • ✅ JVM-specific libraries (Jackson, OkHttp, url-detector)
  • ✅ Android implementation = Desktop implementation (same JVM)
  • ✅ Library doesn't work on iOS/web
Do NOT use jvmAndroid for:
  • ❌ Pure Kotlin code (use commonMain)
  • ❌ Platform-specific APIs (use androidMain/jvmMain)
  • ❌ Code that should work on all platforms
在以下场景使用jvmAndroid:
  • ✅ JVM专属库(Jackson、OkHttp、url-detector)
  • ✅ Android实现与桌面端实现一致(基于相同JVM)
  • ✅ 该库不支持iOS/Web
请勿在以下场景使用jvmAndroid:
  • ❌ 纯Kotlin代码(应使用commonMain)
  • ❌ 平台特定API(应使用androidMain/jvmMain)
  • ❌ 需要在所有平台运行的代码

Example from quartz/build.gradle.kts

quartz/build.gradle.kts中的示例

kotlin
// Must be defined BEFORE androidMain and jvmMain
val jvmAndroid = create("jvmAndroid") {
    dependsOn(commonMain.get())

    dependencies {
        api(libs.jackson.module.kotlin)  // JSON parsing - JVM only
        api(libs.url.detector)            // URL extraction - JVM only
        implementation(libs.okhttp)       // HTTP client - JVM only
    }
}

// Both depend on jvmAndroid
jvmMain { dependsOn(jvmAndroid) }
androidMain { dependsOn(jvmAndroid) }
Why Jackson in jvmAndroid, not commonMain?
  • Jackson is JVM-specific library
  • Works on Android (runs on JVM)
  • Works on Desktop (runs on JVM)
  • Does NOT work on iOS (not JVM) or web (not JVM)
Web/wasm consideration: For future web support, consider migrating from Jackson → kotlinx.serialization (see Target-Specific Guidance).
kotlin
// 必须在androidMain和jvmMain之前定义
val jvmAndroid = create("jvmAndroid") {
    dependsOn(commonMain.get())

    dependencies {
        api(libs.jackson.module.kotlin)  // JSON解析 - 仅JVM支持
        api(libs.url.detector)            // URL提取 - 仅JVM支持
        implementation(libs.okhttp)       // HTTP客户端 - 仅JVM支持
    }
}

// 两者都依赖jvmAndroid
jvmMain { dependsOn(jvmAndroid) }
androidMain { dependsOn(jvmAndroid) }
为什么Jackson放在jvmAndroid而不是commonMain?
  • Jackson是JVM专属库
  • 可在Android(基于JVM运行)使用
  • 可在桌面端(基于JVM运行)使用
  • 不支持iOS(非JVM)或Web(非JVM)
Web/WASM考量: 为了未来的Web支持,考虑从Jackson迁移到kotlinx.serialization(参见目标平台专属指南)。

What to Abstract vs Keep Platform-Specific

哪些内容需要抽象,哪些保留平台特定实现

Quick decision guidelines based on codebase patterns:
基于代码库模式的快速决策指南:

Always Abstract

始终抽象

  • Crypto (Secp256k1, encryption, signing)
  • Core protocol logic (Nostr events, NIPs)
  • Why: Needed everywhere, platform security APIs vary
  • 加密模块(Secp256k1、加密、签名)
  • 核心协议逻辑(Nostr事件、NIP标准)
  • 原因: 所有平台都需要,且各平台的安全API不同

Often Abstract

通常抽象

  • I/O operations (file reading, caching)
  • Logging (platform logging systems differ)
  • Serialization (if using kotlinx.serialization)
  • Why: Commonly reused, platform implementations available
  • I/O操作(文件读取、缓存)
  • 日志(各平台的日志系统不同)
  • 序列化(如果使用kotlinx.serialization)
  • 原因: 普遍需要复用,且有成熟的平台实现

Sometimes Abstract

有时抽象

  • Business logic: YES - state machines, data processing
  • ViewModels: YES - state + business logic shareable (StateFlow/SharedFlow)
  • Screen layouts: NO - platform-native (Window vs Activity)
  • Why: ViewModels contain platform-agnostic state; Screens render differently per platform
  • 业务逻辑: 是 - 状态机、数据处理
  • ViewModels: 是 - 状态+业务逻辑可共享(StateFlow/SharedFlow)
  • 屏幕布局: 否 - 平台原生实现(Window vs Activity)
  • 原因: ViewModels包含与平台无关的状态;屏幕在各平台的渲染方式不同

Rarely Abstract

很少抽象

  • Complex UI components (composables with heavy platform dependencies)
  • Why: Platform paradigms can differ significantly
  • 复杂UI组件(依赖大量平台API的Composable组件)
  • 原因: 各平台的范式差异显著

Never Abstract

绝不抽象

  • Navigation (Activity vs Window fundamentally different)
  • Permissions (Android vs iOS APIs incompatible)
  • Platform UX patterns
  • Why: Too platform-specific, abstraction creates leaky APIs
  • 导航(Activity与Window存在根本性差异)
  • 权限(Android与iOS API不兼容)
  • 平台UX模式
  • 原因: 与平台绑定过深,抽象会导致API泄漏

Evidence from shared-ui-analysis.md

shared-ui-analysis.md中的依据

ComponentShared?Rationale
PubKeyFormatter, ZapFormatter✅ YESPure Kotlin, no platform APIs
TimeAgoFormatter⚠️ ABSTRACTEDNeeds StringProvider for localized strings
ViewModels (state + logic)✅ YESStateFlow/SharedFlow platform-agnostic, Compose Multiplatform lifecycle compatible
Screen layouts (Scaffold, nav)❌ NOWindow vs Activity, sidebar vs bottom nav fundamentally different
Image loading (Coil)⚠️ ABSTRACTEDCoil 3.x supports KMP, needs expect/actual wrapper
组件是否共享?理由
PubKeyFormatter, ZapFormatter✅ 是纯Kotlin实现,无平台API
TimeAgoFormatter⚠️ 已抽象需要StringProvider来处理本地化字符串
ViewModels(状态+逻辑)✅ 是StateFlow/SharedFlow与平台无关,兼容Compose Multiplatform生命周期
屏幕布局(Scaffold、导航)❌ 否Window与Activity、侧边栏与底部导航存在根本性差异
图片加载(Coil)⚠️ 已抽象Coil 3.x支持KMP,需要expect/actual包装器

expect/actual Mechanics

expect/actual 机制

When to use: Code needed by 2+ platforms, varies by platform.
使用场景: 2个及以上平台需要使用,但各平台实现不同的代码。

Pattern Categories from Codebase

代码库中的模式分类

Objects (singletons):
kotlin
// 24 expect declarations found, common pattern:
expect object Secp256k1Instance { ... }
expect object Log { ... }
expect object LibSodiumInstance { ... }
Classes (instantiable):
kotlin
expect class AESCBC { ... }
expect class DigestInstance { ... }
Functions (utilities):
kotlin
expect fun platform(): String
expect fun currentTimeSeconds(): Long
See references/expect-actual-catalog.md for complete catalog with rationale.
对象(单例):
kotlin
// 已找到24个expect声明,常见模式:
expect object Secp256k1Instance { ... }
expect object Log { ... }
expect object LibSodiumInstance { ... }
类(可实例化):
kotlin
expect class AESCBC { ... }
expect class DigestInstance { ... }
函数(工具类):
kotlin
expect fun platform(): String
expect fun currentTimeSeconds(): Long
参考 references/expect-actual-catalog.md 获取完整的声明列表及抽象理由。

Target-Specific Guidance

目标平台专属指南

Android, JVM (Desktop), iOS - Current Primary Targets

Android、JVM(桌面端)、iOS - 当前主要目标平台

Status: Mature patterns, stable APIs
Android (androidMain):
  • Uses Android framework (Activity, Context, etc.)
  • secp256k1-kmp-jni-android for crypto
  • AndroidX libraries
Desktop JVM (jvmMain):
  • Uses Compose Desktop (Window, MenuBar, etc.)
  • secp256k1-kmp-jni-jvm for crypto
  • Pure JVM libraries
iOS (iosMain):
  • Active development, framework configured
  • Architecture targets: iosX64Main, iosArm64Main, iosSimulatorArm64Main
  • Platform APIs via platform.posix, Security framework
状态: 模式成熟,API稳定
Android(androidMain):
  • 使用Android框架(Activity、Context等)
  • 使用secp256k1-kmp-jni-android处理加密
  • 使用AndroidX库
桌面端JVM(jvmMain):
  • 使用Compose Desktop(Window、菜单栏等)
  • 使用secp256k1-kmp-jni-jvm处理加密
  • 使用纯JVM库
iOS(iosMain):
  • 开发中,框架已配置
  • 架构目标:iosX64Main、iosArm64Main、iosSimulatorArm64Main
  • 通过platform.posix、Security框架使用平台API

Web, wasm - Future Targets

Web、WASM - 未来目标平台

Status: Not yet implemented, consider for future-proofing
Constraints to know:
  • ❌ No platform.posix (file I/O different)
  • ❌ No JVM libraries (Jackson, OkHttp won't work)
  • ❌ Different async model (JS event loop vs threads)
Future-proofing tips:
  1. Prefer pure Kotlin in commonMain
  2. Use kotlinx.* libraries:
    • kotlinx.serialization instead of Jackson
    • ktor instead of OkHttp (ktor supports web)
    • kotlinx.datetime instead of custom date handling
  3. Avoid platform.posix for file operations
  4. Test abstractions work without JVM assumptions
Example migration path:
kotlin
// Current: jvmAndroid (JVM-only)
api(libs.jackson.module.kotlin)

// Future: commonMain (all platforms)
api(libs.kotlinx.serialization.json)
状态: 尚未实现,需考虑未来兼容性
需要了解的限制:
  • ❌ 无platform.posix支持(文件I/O方式不同)
  • ❌ 不支持JVM库(Jackson、OkHttp无法使用)
  • ❌ 异步模型不同(JS事件循环 vs 线程)
未来兼容性建议:
  1. 优先在commonMain中使用纯Kotlin代码
  2. 使用kotlinx.*库:
    • 使用kotlinx.serialization替代Jackson
    • 使用ktor替代OkHttp(ktor支持Web)
    • 使用kotlinx.datetime替代自定义日期处理
  3. 避免使用platform.posix进行文件操作
  4. 测试抽象实现不依赖JVM假设
示例迁移路径:
kotlin
// 当前:jvmAndroid(仅JVM支持)
api(libs.jackson.module.kotlin)

// 未来:commonMain(全平台支持)
api(libs.kotlinx.serialization.json)

Integration: When to Invoke Other Skills

集成:何时调用其他技能

Invoke gradle-expert

调用gradle-expert

Trigger gradle-expert skill when encountering:
  • Dependency conflicts (e.g., secp256k1-android vs secp256k1-jvm version mismatch)
  • Build errors related to source sets
  • Version catalog issues (libs.versions.toml)
  • "Duplicate class" errors
  • Performance/build time issues
Example trigger:
Error: Duplicate class found: fr.acinq.secp256k1.Secp256k1
→ Invoke gradle-expert for dependency conflict resolution.
在遇到以下情况时,调用gradle-expert技能:
  • 依赖冲突(例如secp256k1-android与secp256k1-jvm版本不匹配)
  • 与源码集相关的构建错误
  • 版本目录问题(libs.versions.toml)
  • “重复类”错误
  • 性能/构建时间问题
示例触发场景:
Error: Duplicate class found: fr.acinq.secp256k1.Secp256k1
→ 调用gradle-expert解决依赖冲突。

Flags to Raise

需要标记的问题

Platform code in commonMain:
kotlin
// ❌ INCORRECT - Android API in commonMain
expect fun getContext(): Context  // Context is Android-only!
→ Flag: "Android API in commonMain won't compile on other platforms"
Duplicated business logic:
kotlin
// ❌ INCORRECT - Same logic in both
// androidMain/.../CryptoUtils.kt
fun validateSignature(...) { ... }

// jvmMain/.../CryptoUtils.kt
fun validateSignature(...) { ... }  // Duplicated!
→ Flag: "Business logic duplicated, should be in commonMain or expect/actual"
Reinventing wheel - suggest KMP alternatives:
  • Custom date/time → kotlinx.datetime
  • OkHttp → ktor (supports web)
  • Jackson → kotlinx.serialization
  • Custom UUID → kotlinx.uuid (when stable)
commonMain中包含平台代码:
kotlin
// ❌ 错误 - commonMain中包含Android API
expect fun getContext(): Context  // Context是Android专属API!
→ 标记:“commonMain中的Android API无法在其他平台编译”
重复的业务逻辑:
kotlin
// ❌ 错误 - 两段代码逻辑完全相同
// androidMain/.../CryptoUtils.kt
fun validateSignature(...) { ... }

// jvmMain/.../CryptoUtils.kt
fun validateSignature(...) { ... }  // 重复实现!
→ 标记:“业务逻辑重复,应放在commonMain或使用expect/actual”
重复造轮子 - 建议使用KMP替代方案:
  • 自定义日期/时间 → kotlinx.datetime
  • OkHttp → ktor(支持Web)
  • Jackson → kotlinx.serialization
  • 自定义UUID → kotlinx.uuid(稳定后)

Common Pitfalls

常见陷阱

1. Over-Abstraction

1. 过度抽象

Problem: Creating expect/actual for UI components
kotlin
// ❌ BAD
expect fun NavigationComponent(...)
Why: Navigation paradigms too different (Activity vs Window) Fix: Keep platform-specific, accept duplication
问题: 为UI组件创建expect/actual
kotlin
// ❌ 错误
expect fun NavigationComponent(...)
原因: 导航范式差异过大(Activity vs Window) 修复: 保留平台特定实现,接受代码重复

2. Under-Sharing

2. 共享不足

Problem: Duplicating business logic across platforms
kotlin
// ❌ BAD - duplicated in androidMain and jvmMain
fun parseNostrEvent(json: String): Event { ... }
Why: Bug fixes need to be applied twice, tests duplicated Fix: Move to commonMain (pure Kotlin) or create expect/actual
问题: 跨平台重复业务逻辑
kotlin
// ❌ 错误 - 在androidMain和jvmMain中重复实现
fun parseNostrEvent(json: String): Event { ... }
原因: Bug修复需要在多平台重复进行,测试代码也会重复 修复: 移至commonMain(纯Kotlin)或使用expect/actual

3. Leaky Abstractions

3. 抽象泄漏

Problem: Platform code in commonMain
kotlin
// commonMain - ❌ BAD
import android.content.Context  // Won't compile on iOS!
Fix: Use expect/actual or dependency injection
问题: commonMain中包含平台代码
kotlin
// commonMain - ❌ 错误
import android.content.Context  // 在iOS上无法编译!
修复: 使用expect/actual或依赖注入

4. Premature Abstraction

4. 过早抽象

Problem: Creating expect/actual before second platform needs it
kotlin
// ❌ BAD - only used on Android currently
expect fun showNotification(...)
Why: Wrong abstraction boundaries, wasted effort Fix: Wait until iOS actually needs it, then abstract
问题: 在第二个平台需要之前就创建expect/actual
kotlin
// ❌ 错误 - 当前仅在Android上使用
expect fun showNotification(...)
原因: 抽象边界错误,浪费精力 修复: 等到iOS确实需要时再进行抽象

5. Wrong Source Set

5. 源码集放置错误

Problem: JVM libraries in commonMain
kotlin
// commonMain - ❌ BAD
import com.fasterxml.jackson.databind.ObjectMapper
Why: Jackson won't compile on iOS/web Fix: Move to jvmAndroid or migrate to kotlinx.serialization
问题: commonMain中包含JVM库
kotlin
// commonMain - ❌ 错误
import com.fasterxml.jackson.databind.ObjectMapper
原因: Jackson无法在iOS/Web上编译 修复: 移至jvmAndroid或迁移到kotlinx.serialization

Quick Reference

快速参考

Code TypeRecommended LocationReason
Pure Kotlin business logiccommonMainWorks everywhere
Nostr protocol, NIPscommonMainCore logic, no platform APIs
JVM libs (Jackson, OkHttp)jvmAndroidAndroid + Desktop only
Crypto (varies by platform)expect in commonMain, actual in platformsDifferent security APIs per platform
I/O, loggingexpect in commonMain, actual in platformsPlatform implementations differ
State (business logic)commonMain or commons/jvmAndroidReusable StateFlow patterns
ViewModelscommons/commonMain/viewmodels/StateFlow/SharedFlow + logic shareable, Compose MP lifecycle compatible
UI formatters (pure)commons/commonMainReusable, no dependencies
UI components (simple)commons/commonMainCards, buttons, dialogs
Screen layoutsPlatform-specificWindow vs Activity, sidebar vs bottom nav
NavigationPlatform-specific onlyActivity vs Window too different
PermissionsPlatform-specific onlyAPIs incompatible
Platform UX (menus, etc.)Platform-specific onlyNative feel required
代码类型推荐放置位置理由
纯Kotlin业务逻辑commonMain全平台可用
Nostr协议、NIP标准commonMain核心逻辑,无平台API
JVM库(Jackson、OkHttp)jvmAndroid仅Android + 桌面端支持
加密(平台实现不同)commonMain中声明expect,平台源码集中实现actual各平台安全API不同
I/O、日志commonMain中声明expect,平台源码集中实现actual各平台实现不同
状态(业务逻辑)commonMain或commons/jvmAndroid可复用StateFlow模式
ViewModelscommons/commonMain/viewmodels/StateFlow/SharedFlow + 逻辑可共享,兼容Compose MP生命周期
UI格式化工具(纯实现)commons/commonMain可复用,无依赖
UI组件(简单)commons/commonMain卡片、按钮、对话框
屏幕布局平台特定源码集Window vs Activity、侧边栏 vs 底部导航差异显著
导航仅平台特定源码集Activity与Window差异过大
权限仅平台特定源码集API不兼容
平台UX(菜单等)仅平台特定源码集需要原生体验

See Also

参考链接

  • references/abstraction-examples.md - Good/bad abstraction examples with rationale
  • references/source-set-hierarchy.md - Visual hierarchy with Amethyst examples
  • references/expect-actual-catalog.md - All 24 expect/actual pairs with "why abstracted"
  • references/target-compatibility.md - Platform constraints and future-proofing
  • references/abstraction-examples.md - 抽象的正反示例及理由
  • references/source-set-hierarchy.md - 带Amethyst示例的可视化层级结构
  • references/expect-actual-catalog.md - 全部24个expect/actual对及“为何抽象”的说明
  • references/target-compatibility.md - 平台限制及未来兼容性指南

Scripts

脚本

  • scripts/validate-kmp-structure.sh
    - Detect incorrect placements, validate source sets
  • scripts/suggest-kmp-dependency.sh
    - Suggest KMP library alternatives (ktor, kotlinx.serialization, etc.)
  • scripts/validate-kmp-structure.sh
    - 检测代码的错误放置,验证源码集结构
  • scripts/suggest-kmp-dependency.sh
    - 推荐KMP库替代方案(ktor、kotlinx.serialization等)