Agent Skillschrisbanes/skills › kotlin-multiplatform-expect-actual

kotlin-multiplatform-expect-actual

GitHub

用于设计 Kotlin Multiplatform 项目的 expect/actual 边界及平台服务接口。指导如何将平台特定实现与通用代码解耦,保持 API 语义化,选择最小边界,并确保实际实现层薄且仅负责翻译,避免业务逻辑泄露至平台绑定层。

skills/kotlin-multiplatform-expect-actual/SKILL.md chrisbanes/skills

Trigger Scenarios

设计 Kotlin Multiplatform 的 expect/actual 声明 定义跨平台服务接口或 UI 边界 处理 Android/iOS/Desktop 的平台互操作性 重构以分离通用逻辑与平台特定细节

Install

npx skills add chrisbanes/skills --skill kotlin-multiplatform-expect-actual -g -y
More Options

Use without installing

npx skills use chrisbanes/skills@kotlin-multiplatform-expect-actual

指定 Agent (Claude Code)

npx skills add chrisbanes/skills --skill kotlin-multiplatform-expect-actual -a claude-code -g -y

安装 repo 全部 skill

npx skills add chrisbanes/skills --all -g -y

预览 repo 内 skill

npx skills add chrisbanes/skills --list

SKILL.md

Frontmatter
{
    "name": "kotlin-multiplatform-expect-actual",
    "description": "Use when designing Kotlin Multiplatform expect\/actual or interface boundaries for platform services, native SDKs, source sets, Compose Multiplatform UI, permissions, files, settings, sensors, or platform interop."
}

Kotlin Multiplatform: expect/actual boundaries

Core principle

Keep common APIs semantic and stable. Put platform mechanics behind small expect/actual declarations or interfaces, and keep Android/iOS/Desktop details out of commonMain.

Boundary procedure

  1. Name the product capability in common terms: share text, read clipboard, request haptic feedback, resolve current region.
  2. Check whether common callers need fakes, injected dependencies, lifecycle ownership, or runtime implementation choice.
  3. Pick the smallest boundary from the table below.
  4. Keep the common signature free of platform types and platform vocabulary.
  5. Put business branching in common code; keep actuals/platform bindings as translation layers.
  6. Validate by compiling every affected source set and testing common code with a fake where possible.

Choose the boundary

Situation Prefer
Simple compile-time platform specialization expect/actual function, value, typealias, or leaf composable
Implementation needs injected dependencies, lifecycle ownership, runtime choice, or test fakes Common interface plus platform binding
UI is mostly shared, one leaf differs Common composable calling an expect leaf
Entire screen differs by platform Separate platform screens behind a common navigation contract
Only constants/resources differ Common API exposing semantic values, actual values per platform

Keep common APIs semantic

Write common APIs so callers describe intent, not platform mechanics:

// GOOD: common API is semantic
expect fun currentRegion(): Region
// BAD: common API leaks Android implementation
expect fun currentRegionFromAndroidLocale(context: Context): Region

The Android actual can use Locale APIs. The iOS actual can use Foundation APIs. Common callers should not know.

Keep actuals thin

Actual implementations should translate the semantic API into platform calls. If the operation needs an Activity, view controller, lifecycle owner, DI, or fakes, stop and use an interface supplied by platform code instead of an expect class:

// commonMain
interface ShareSheet {
    suspend fun shareText(text: String)
}
// androidMain
class AndroidShareSheet(
    private val activity: Activity,
) : ShareSheet {
    override suspend fun shareText(text: String) {
        val intent = Intent(Intent.ACTION_SEND)
            .setType("text/plain")
            .putExtra(Intent.EXTRA_TEXT, text)
        activity.startActivity(Intent.createChooser(intent, null))
    }
}

The Android implementation is explicitly Activity-owned. A generic Context often hides the UI lifecycle requirement. Define what suspend means: for many platform UI actions it means "the sheet was launched", not "the user completed sharing."

If the actual starts accumulating business rules, move those rules back to common code and leave only platform translation in the actual.

Prefer interfaces when tests or DI matter

Use expect/actual for simple compile-time platform APIs. Use interfaces when common code needs fakes, multiple implementations, runtime selection, or lifecycle ownership:

interface Clipboard {
    suspend fun setText(text: String)
}

Platform modules bind Clipboard to Android/iOS implementations. Common tests use a fake.

Compose-specific guidance

When shared UI reaches a platform leaf:

  1. Keep platform-specific composables at leaf nodes.
  2. Pass Modifier through every expected composable that emits UI.
  3. Reject platform types in commonMain signatures (Context, Activity, Android resource IDs, Uri, Bundle, UIViewController, NSBundle, platform permission enums, etc.).
  4. Hide native view lifecycle inside the platform actual and use the right interop container (AndroidView, UIKitView, etc.).
  5. Do not launch platform work directly from a composable body. Use remember, LaunchedEffect, DisposableEffect, and stable keys inside actual composables just as you would in common Compose code.
  6. Preview/test the common plain UI composable with fake platform services where possible.

Common mistakes

Mistake Fix
commonMain API exposes Android/iOS types Replace with semantic common types
expect function has parameters for one platform only Move those details into the actual
Business branching duplicated in each actual Move business rules to common code
One huge Platform expect object Split by capability: Clipboard, ShareSheet, Haptics
Platform UI leaks high in the tree Push platform-specific Composable to a leaf
No fakeable boundary for common tests Use an interface instead of direct expect call
Only one target compiles after the change Compile all affected source sets before finishing

Red flags during review

  • Common code imports platform packages.
  • An actual implementation knows product state, navigation decisions, or domain rules.
  • A platform API name appears in a common function name.
  • Adding a third platform would require changing common callers.
  • Tests need Android/iOS runtime just to verify common business behavior.

Related (Compose / shared UI)

Stay focused on platform boundaries in this skill; wire shared UI like any other Compose target:

Version History

  • 2026.7.21 Current 2026-07-24 12:25

Same Skill Collection

skills/compose-animations/SKILL.md
skills/compose-focus-navigation/SKILL.md
skills/compose-modifier-and-layout-style/SKILL.md
skills/compose-recomposition-performance/SKILL.md
skills/compose-side-effects/SKILL.md
skills/compose-slot-api-pattern/SKILL.md
skills/compose-stability-diagnostics/SKILL.md
skills/compose-state-authoring/SKILL.md
skills/compose-state-deferred-reads/SKILL.md
skills/compose-state-hoisting/SKILL.md
skills/compose-state-holder-ui-split/SKILL.md
skills/compose-ui-testing-patterns/SKILL.md
skills/implement-issue/SKILL.md
skills/kotlin-control-flow/SKILL.md
skills/kotlin-coroutines-structured-concurrency/SKILL.md
skills/kotlin-flow-state-event-modeling/SKILL.md
skills/kotlin-functions/SKILL.md
skills/kotlin-types-value-class/SKILL.md
skills/shepherd/SKILL.md
skills/using-chrisbanes-skills/SKILL.md

Metadata

Files
0
Version
2026.7.21
Hash
0e2d3c1a
Indexed
2026-07-24 12:25

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-07 07:19
浙ICP备14020137号-1 $Carte des visiteurs$