kotlin-multiplatform
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseKotlin 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 frameworkWhy: 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: (Activity + Compose Navigation)
MainActivity - Desktop: + sidebar + MenuBar Why: UI paradigms fundamentally different.
Window
加密模块 → 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:(Activity + Compose Navigation)
MainActivity - 桌面端:+ 侧边栏 + 菜单栏 原因: UI范式存在根本性差异。
Window
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, wasmMainKey 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中的依据
| Component | Shared? | Rationale |
|---|---|---|
| PubKeyFormatter, ZapFormatter | ✅ YES | Pure Kotlin, no platform APIs |
| TimeAgoFormatter | ⚠️ ABSTRACTED | Needs StringProvider for localized strings |
| ViewModels (state + logic) | ✅ YES | StateFlow/SharedFlow platform-agnostic, Compose Multiplatform lifecycle compatible |
| Screen layouts (Scaffold, nav) | ❌ NO | Window vs Activity, sidebar vs bottom nav fundamentally different |
| Image loading (Coil) | ⚠️ ABSTRACTED | Coil 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(): LongSee 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:
- Prefer pure Kotlin in commonMain
- Use kotlinx.* libraries:
- kotlinx.serialization instead of Jackson
- ktor instead of OkHttp (ktor supports web)
- kotlinx.datetime instead of custom date handling
- Avoid platform.posix for file operations
- 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 线程)
未来兼容性建议:
- 优先在commonMain中使用纯Kotlin代码
- 使用kotlinx.*库:
- 使用kotlinx.serialization替代Jackson
- 使用ktor替代OkHttp(ktor支持Web)
- 使用kotlinx.datetime替代自定义日期处理
- 避免使用platform.posix进行文件操作
- 测试抽象实现不依赖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.ObjectMapperWhy: 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 Type | Recommended Location | Reason |
|---|---|---|
| Pure Kotlin business logic | commonMain | Works everywhere |
| Nostr protocol, NIPs | commonMain | Core logic, no platform APIs |
| JVM libs (Jackson, OkHttp) | jvmAndroid | Android + Desktop only |
| Crypto (varies by platform) | expect in commonMain, actual in platforms | Different security APIs per platform |
| I/O, logging | expect in commonMain, actual in platforms | Platform implementations differ |
| State (business logic) | commonMain or commons/jvmAndroid | Reusable StateFlow patterns |
| ViewModels | commons/commonMain/viewmodels/ | StateFlow/SharedFlow + logic shareable, Compose MP lifecycle compatible |
| UI formatters (pure) | commons/commonMain | Reusable, no dependencies |
| UI components (simple) | commons/commonMain | Cards, buttons, dialogs |
| Screen layouts | Platform-specific | Window vs Activity, sidebar vs bottom nav |
| Navigation | Platform-specific only | Activity vs Window too different |
| Permissions | Platform-specific only | APIs incompatible |
| Platform UX (menus, etc.) | Platform-specific only | Native 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模式 |
| ViewModels | commons/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
脚本
- - Detect incorrect placements, validate source sets
scripts/validate-kmp-structure.sh - - Suggest KMP library alternatives (ktor, kotlinx.serialization, etc.)
scripts/suggest-kmp-dependency.sh
- - 检测代码的错误放置,验证源码集结构
scripts/validate-kmp-structure.sh - - 推荐KMP库替代方案(ktor、kotlinx.serialization等)
scripts/suggest-kmp-dependency.sh