mcpField
K
kotlin-multiplatform

kotlin-multiplatform

github.com/travisjneuman開発107180 回インストール1 日前に更新
リポジトリ

kotlin-multiplatform について

kotlin-multiplatform は、Kotlin Multiplatform プロジェクトを開発し、Android、iOS、デスクトップ、Web 間でビジネスロジックを共有する開発者向けのスキルガイドです。プロジェクト構成、プラットフォーム別実装、ネットワーク、ストレージ、UI 連携、テストを扱います。

主な機能

  1. 01マルチプラットフォーム構成例
  2. 02expect/actual による実装パターン
  3. 03Ktor によるネットワーク処理
  4. 04SQLDelight によるローカル保存
  5. 05Compose Multiplatform の共有 UI
  6. 06共有コードのテスト指針

活用シーン

  1. 01共有ロジックとプラットフォーム固有コードの設計
  2. 02マルチプラットフォームアプリへの通信と保存の実装
  3. 03common モジュールの共有コードのテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/travisjneuman/.claude --skill kotlin-multiplatform

インストール後、Claude Code で/kotlin-multiplatformを入力して読み込まれたか確認します。

詳細

Kotlin Multiplatform スキル

Android、iOS、デスクトップ、ウェブ間でビジネスロジックを共有し、必要に応じて UI も共有できます。


プロジェクト構成

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

expect/actual パターン

// 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() }
}

主なライブラリ

ライブラリ用途マルチプラットフォーム対応
KtorHTTP クライアント対応
kotlinx.serializationJSON の解析対応
kotlinx.coroutines非同期処理/並行処理対応
SQLDelightローカルデータベース対応
Koin依存性注入対応
Compose MultiplatformUI の共有対応
kotlinx.datetime日付/時刻対応
Napierロギング対応

Ktor によるネットワーク通信

// 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,
)

SQLDelight によるローカルストレージ

-- 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 = ?;

Compose Multiplatform UI

// 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) })
                }
            }
        }
    }
}

iOS との統合

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
        })
    }
}
CocoaPods または SPM との統合
// build.gradle.kts
kotlin {
    iosX64()
    iosArm64()
    iosSimulatorArm64()

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

テスト

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

    @Test
    fun fetchUsersReturnsListFromApi() = runTest {
        fakeApi.setUsers(listOf(User("1", "Alice", "[email protected]")))

        val users = repository.getUsers()

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

ベストプラクティス

  • ビジネスロジック(ネットワーク通信、ストレージ、モデル)を共有し、必要に応じてプラットフォーム固有の UI を使用します
  • expect/actual の使用は最小限にとどめ、DI を通じてプラットフォームごとに実装するインターフェースを優先します
  • 共有モジュールは薄く保ち、プラットフォームに強く依存する依存関係を取り込まないようにします
  • 共有コードは commonTest でテストします。すべてのターゲットで実行されます
  • ネイティブの外観が重要でない新規プロジェクトでは、Compose Multiplatform を使用します

関連リソース

  • ~/.claude/skills/android-development/SKILL.md - Android のパターン
  • ~/.claude/skills/ios-development/SKILL.md - iOS のパターン
  • agent-flutter-developer スキル - クロスプラットフォーム開発の代替手段

ロジックを共有し、各プラットフォームを尊重しましょう。KMP なら両方の長所を活かせます。

コメント