Contents
Kotlin Multiplatform の概要とメリット
Kotlin Multiplatform (KMP) は、1 つのコードベースで Android・iOS・macOS・Linux・Web といった複数プラットフォーム向けにビジネスロジックを共有できる仕組みです。このセクションでは、実際に期待できるコード共有率や保守性の向上といった具体的な効果を示し、本ガイド全体で扱うテーマの位置付けを明確にします。
- コード共有率:公式ドキュメントや JetBrains の開発者調査(2023 年)では、UI 以外のロジックが 70 % 前後 まで共通化できるケースが多いと報告されています[^1]。
- 保守コストの削減:バグ修正や機能追加は
commonMainに 1 回書くだけで全プラットフォームに反映され、テストコードも統一できるためリリースサイクルが短縮します。 - 開発者体験の向上:Kotlin 1.9 系と Gradle Kotlin DSL の組み合わせにより、IDE が提供するコード補完・リファクタリング支援をフル活用できます。
KMP を導入すれば「同じロジックを複数回書く」必要がなくなり、品質と開発速度の両面でメリットが得られます。
開発環境のセットアップと Gradle Kotlin DSL 設定
KMP プロジェクトは、最新の IDE とツールチェーンをベースに構築することが推奨されます。このセクションでは、IntelliJ IDEA または Android Studio のインストール手順と、Kotlin 1.9 系・Gradle Kotlin DSL (KTS) を用いた基本設定方法を解説します。
IntelliJ IDEA / Android Studio のインストール
まず公式サイトから IntelliJ IDEA Community(または Ultimate) もしくは Android Studio Flamingo をダウンロードし、インストーラの指示に従ってインストールしてください。
インストール後は「Check for updates」を有効化して常に最新バージョンを保ちます。また、Plugins → Kotlin でプラグインが有効になっていることを確認します。
詳細な手順は Android Developers が提供する公式 Codelab([KMP 入門])をご参照ください。
Kotlin プラグインと JDK の設定
- Kotlin プラグインは IDE に同梱されていますが、バージョンは 1.9.x 以上 を使用してください。
- JDKは少なくとも JDK 22(LTS)を選択し、
Project Structure → SDKsで設定します。
Gradle Kotlin DSL の基本構成例
以下は典型的な build.gradle.kts(ルート)の雛形です。プラグインやリポジトリの宣言だけでなく、共通設定を allprojects に集約しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
plugins { kotlin("multiplatform") version "1.9.24" id("com.android.application") version "8.4.0" apply false } repositories { google() mavenCentral() } // すべてのサブプロジェクトで共通リポジトリを使用 allprojects { repositories { google() mavenCentral() } } |
プラットフォーム別 sourceSet の設定
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
kotlin { androidTarget() iosX64() iosArm64() js(IR) { browser() } sourceSets { val commonMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") } } val androidMain by getting val iosMain by creating { dependsOn(commonMain) } val jsMain by getting { dependencies { implementation("io.ktor:ktor-client-js:2.3.6") } } } } |
上記構成は公式ガイドの「マルチプラットフォームプロジェクトのセットアップ」と同等です。
プロジェクト構成とモジュール分割のベストプラクティス
大規模アプリでも管理しやすいディレクトリ構造を設計することは、KMP 成功の鍵となります。この章では、shared, androidApp, iosApp の典型的なモジュール構成と、それぞれが担う役割を具体例で示します。
典型的なディレクトリ構造
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
my-kmp-project/ ├─ build.gradle.kts ├─ settings.gradle.kts ├─ shared/ // 共通ロジック (commonMain / commonTest) │ └─ src/ │ ├─ commonMain/kotlin/ │ └─ commonTest/kotlin/ ├─ androidApp/ // Android アプリモジュール │ └─ src/main/kotlin/ ├─ iosApp/ // iOS アプリ(Xcode 連携) │ └─ src/main/kotlin/ └─ buildSrc/ // カスタムプラグイン・バージョン管理 |
shared:データモデル、リポジトリ、Coroutines などビジネスロジックを配置。テストはcommonTestにまとめることで、全プラットフォームで同一テストが走ります。androidApp/iosApp:プラットフォーム固有の UI やシステム API 呼び出しを保持し、sharedに依存します。
sourceSet の関係性
|
1 2 3 4 5 6 7 8 |
kotlin { sourceSets { val commonMain by getting val androidMain by getting { dependsOn(commonMain) } val iosMain by creating { dependsOn(commonMain) } } } |
この構成は公式ガイドでも推奨されており、コードの所在が明確でビルド時間も最適化できます。
共通コード実装と expect/actual パターン
KMP の核となる機能は expect/actual によるプラットフォーム抽象化です。この章では、シンプルな TODO アプリを例にデータモデル・リポジトリ・Coroutine スコープの実装方法と、期待インターフェース/実装の分離手順を示します。
commonMain におけるデータモデルとビジネスロジック
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// shared/src/commonMain/kotlin/model/TodoItem.kt data class TodoItem( val id: Long, val title: String, val completed: Boolean = false ) // shared/src/commonMain/kotlin/repository/TodoRepository.kt interface TodoRepository { suspend fun getAll(): List<TodoItem> suspend fun add(item: TodoItem) suspend fun toggleCompleted(id: Long) } |
Coroutine スコープの提供
|
1 2 3 4 5 6 7 8 9 10 |
// shared/src/commonMain/kotlin/util/ScopeProvider.kt import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlin.native.concurrent.ThreadLocal @ThreadLocal // iOS のシングルトン化に必須 object ScopeProvider { val ioScope = CoroutineScope(Dispatchers.IO) } |
expect / actual によるプラットフォーム固有 API
期待インターフェース(共通側)
|
1 2 3 |
// shared/src/commonMain/kotlin/platform/Logger.kt expect fun logDebug(message: String) |
Android 実装
|
1 2 3 4 5 6 7 |
// androidApp/src/main/kotlin/platform/Logger.android.kt import android.util.Log actual fun logDebug(message: String) { Log.d("KMP_SAMPLE", message) } |
iOS 実装
|
1 2 3 4 5 6 7 |
// iosApp/src/main/kotlin/platform/Logger.ios.kt import platform.Foundation.NSLog actual fun logDebug(message: String) { NSLog(message) } |
expect/actualにより 「共通ロジックはプラットフォーム非依存」 で記述でき、実装だけを切り替えることで差分が解消されます。
プラットフォーム別ビルド・デバッグと推奨ライブラリ導入
KMP は Kotlin /Native(iOS)と Kotlin /JS の両方を対象にできます。本章ではそれぞれのビルド設定、デバッグ手順、および 2024 年時点で実務的に利用されている主要ライブラリの導入例を紹介します。
iOS(Kotlin /Native)ビルドと Xcode デバッグ
- Gradle タスク
./gradlew iosX64BinariesまたはiosArm64Binariesを実行し、.frameworkが生成されます。 - Xcode で新規プロジェクトを作成し、Framework Search Paths に
build/bin/iosX64/debugFramework(またはiosArm64)を追加します。 - Swift 側からは
shared.TodoRepository等のクラスをそのまま呼び出せます。ブレークポイントは Xcode のデバッガで有効です。
JS ビルドと Chrome デバッグ
|
1 2 3 4 5 6 |
js(IR) { browser { commonWebpackConfig { cssSupport.enabled = true } } } |
./gradlew jsBrowserDevelopmentRunでローカルサーバが起動し、Chrome DevTools のブレークポイントやネットワークタブを利用できます。
実務で選ばれる主要ライブラリ
| ライブラリ | 用途 | Gradle 依存例 |
|---|---|---|
| Ktor | マルチプラットフォーム HTTP クライアント/サーバ | implementation("io.ktor:ktor-client-core:2.3.6") |
| SQLDelight | ネイティブ対応 SQL データベース | implementation("com.squareup.sqldelight:runtime:2.0.0") |
| MOKO resources | 文字列・画像リソースの統一管理 | implementation("dev.icerock.moko:resources:0.23.0") |
Room から SQLDelight への移行手順(概略)
sharedに SQLDelight のスキーマ (Todo.sq) を作成し、プラグインでコード生成。- Android モジュールでは従来の
RoomDatabaseと併用せず、生成されたTodoQueriesを利用。 - iOS でも同じ Kotlin/Native API が呼び出せるため、データ永続化ロジックが完全に共有されます。
この流れを踏めば、既存 Android アプリの
Room実装からほぼ自動的に KMP 対応へ移行できます。
テスト戦略と CI/CD パイプライン例(GitHub Actions)
KMP プロジェクトでは 共通テスト (commonTest) とプラットフォーム別テスト を組み合わせた品質保証が基本です。この章ではテストコードの配置方法、実行手順、および GitHub Actions による自動ビルド・テストパイプラインを具体例とともに示します。
テストコードの配置と実行
-
commonTest:JUnit5 と Kotlin Test を併用し、ロジック全体を検証。
kotlin
// shared/src/commonTest/kotlin/repository/TodoRepositoryTest.kt
class TodoRepositoryTest {
private val repo = FakeTodoRepository()@Test
funadd item increases size() = runBlocking {
repo.add(TodoItem(1, "Write article"))
assertEquals(1, repo.getAll().size)
}
}
androidUnitTest
- ****:AndroidJUnitRunner を使用し、Android コンテキストが必要なコードを検証。iosTest
- ****:Kotlin/Native のtest タスクで実行し、Xcode のテストレポートに統合可能。
GitHub Actions ワークフロー例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
name: KMP CI on: push: branches: [ main ] pull_request: jobs: build-test: runs-on: macos-latest # iOS ビルドが必要なため macOS を使用 strategy: matrix: platform: [android, ios, js] steps: - uses: actions/checkout@v4 - name: Set up JDK 22 uses: actions/setup-java@v3 with: java-version: '22' distribution: temurin - name: Cache Gradle packages uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - name: Build & Test (${{ matrix.platform }}) run: | case "${{ matrix.platform }}" in android) ./gradlew :androidApp:assembleDebug :shared:testDebugUnitTest ;; ios) ./gradlew iosX64Binaries iosX64Test ;; js) ./gradlew jsBrowserDevelopmentRun jsNodeTest ;; esac |
- マトリクスビルドにより Android、iOS、JS のそれぞれが同時並行で実行されます。
- ビルドが成功すれば GitHub の Checks に結果が表示され、プルリクエストの品質ゲートとして活用できます。
この構成は公式ガイドに基づいた最小限の設定ですが、プロジェクト規模に合わせてデプロイやスナップショット公開のステップを追加可能です。
まとめと次のステップ
Kotlin Multiplatform を採用すると、共通ロジックの再利用率が高まり、保守コストが削減されるだけでなく、テストや CI/CD の自動化も一元管理できます。本ガイドで示した開発環境・プロジェクト構成・expect/actual パターン・推奨ライブラリは、実務ですぐに適用できるベストプラクティスです。次のステップとして、まずは小規模なモジュール(例:認証ロジック)を shared に移行し、ビルドとテストが問題なく走ることを確認してください。
参考文献
[^1]: JetBrains が公開した「Kotlin Multiplatform Survey 2023」― コード共有率は 70 % 前後が一般的という結果(https://blog.jetbrains.com/kotlin/2023/09/kmp-survey-results)