Contents
1. Kotlin Multiplatform の概要と対象プラットフォーム
1-1 KMP が解決する課題
| 課題 | 従来のアプローチ | KMP での解決策 |
|---|---|---|
| コード重複 | 各プラットフォームごとに同一ロジックを実装 | commonMain に共通ロジックを集約し、expect/actual で差分だけ実装 |
| 保守コスト | バグ修正や機能追加が複数リポジトリ/モジュールに波及 | 共通コードは一箇所の変更で全体に反映 |
| ビルド管理 | プラットフォーム別に Gradle ファイルを分割 | 1つの build.gradle.kts でマルチターゲットを宣言 |
ポイント:KMP は「共通ロジックは Kotlin だけで書く」ことと、「プラットフォーム固有実装は必要最小限に抑える」ことが基本設計です。
1-2 主要ターゲット
- JVM / Android
- iOS (Arm64, X64, Simulator)
- JavaScript (ブラウザ/Node.js)
- Native (Linux、Windows、macOS)
1-3 サンプルコード(期待/実装の分離)
|
1 2 3 4 5 |
// commonMain/src/commonMain/kotlin/com/example/shared/Calculator.kt expect class Calculator { fun add(a: Int, b: Int): Int } |
|
1 2 3 4 5 |
// androidApp/src/androidMain/kotlin/com/example/shared/Calculator.android.kt actual class Calculator { override fun add(a: Int, b: Int) = a + b } |
|
1 2 3 4 5 |
// iosApp/src/iosMain/kotlin/com/example/shared/Calculator.ios.kt actual class Calculator { override fun add(a: Int, b: Int) = a + b } |
2. 最新開発環境の構築手順
本稿執筆時点 (2024 年 4 月) の 安定版 を前提としています。バージョンが更新された場合は、公式リリースノートをご確認ください。
2-1 IDE とプラグインの選択
| 項目 | 推奨バージョン | 入手先・根拠 |
|---|---|---|
| IntelliJ IDEA (Community/Ultimate) | 2024.2 系列 | https://www.jetbrains.com/idea/download/ (2024 年 3 月リリースノート) |
| Android Studio | Flamingo 2023.3.1 (2024‑04 更新版) | https://developer.android.com/studio |
| Kotlin プラグイン | 1.9.22(IDE に同梱) | 同上、プラグイン設定画面で自動更新可 |
JetBrains 製品名は「IntelliJ」や「Android Studio」と簡潔にし、過度な繰り返しを避けました。
設定手順(IDE 共通)
- ダウンロードした IDE を起動 → Plugins > Marketplace
Kotlin Multiplatformがインストール済みでない場合は検索して Install- 再起動後、File → New → Project で「Kotlin Multiplatform Mobile (KMM)」テンプレートが選択できることを確認
IDE のバージョン対応表 → https://plugins.jetbrains.com/plugin/6954-kotlin-multiplatform
2-2 Gradle と Kotlin のバージョン管理
|
1 2 3 |
# gradle/wrapper/gradle-wrapper.properties distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip # 公式リリース (2024‑03) |
|
1 2 3 4 5 |
// build.gradle.kts(ルート) plugins { kotlin("multiplatform") version "1.9.22" // 最新安定版 } |
根拠: Gradle 8.5 のリリースノート → https://docs.gradle.org/8.5/release-notes.html、Kotlin 1.9 系列のマルチプラットフォームサポートは公式ドキュメントで推奨されています(https://kotlinlang.org/docs/releases.html#release-1920)。
2-3 JDK の選択
- Android ビルド → JDK 21 が推奨(Android Gradle Plugin 8.1+)
- iOS/Native → 同様に JDK 21 を使用可能。
インストールは SDKMAN! または AdoptOpenJDK の公式サイトから取得してください。
3. KMM Wizard でサンプルプロジェクトを作成
3-1 Wizard の起動と基本オプション
| 手順 | 操作内容 |
|---|---|
| 1 | File → New → Project を選択 |
| 2 | 「Kotlin Multiplatform Mobile」テンプレートを選ぶ |
| 3 | プロジェクト名、保存先、JDK (21) を入力 |
| 4 | Target platforms で Android と iOS にチェック |
| 5 | 「Create sample application」にチェックしてサンプルコード生成 |
UI は IntelliJ の最新版に合わせて微調整されるため、画面が変わっても「KMM Wizard」だけは必ず選択してください(公式ガイド → https://kotlinlang.org/docs/multiplatform-mobile-setup.html#creating-a-project-with-the-wizard)。
3-2 生成されたディレクトリ構造
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
my-kmp-sample/ ├─ settings.gradle.kts ├─ build.gradle.kts // ルート共通設定 ├─ shared/ // KMP ライブラリモジュール │ ├─ src/commonMain/kotlin/ │ │ └─ com/example/shared/Greeting.kt │ ├─ src/androidMain/kotlin/ │ │ └─ com/example/shared/GreetingAndroid.kt │ └─ src/iosMain/kotlin/ │ └─ com/example/shared/GreetingIos.kt ├─ androidApp/ // Android アプリモジュール │ └─ src/main/... // Manifest, UI 等 └─ iosApp/ // iOS アプリ (Xcode プロジェクト) └─ iosApp.xcodeproj |
|
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 |
plugins { kotlin("multiplatform") id("org.jetbrains.compose") version "1.5.2" // UI に Compose Multiplatform を使用する場合 } kotlin { android() iosX64(); iosArm64(); iosSimulatorArm64() sourceSets { val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) // 例: Ktor の共通クライアント implementation("io.ktor:ktor-client-core:2.3.7") } } val androidMain by getting { dependencies { implementation(kotlin("stdlib")) implementation("androidx.core:core-ktx:1.13.0") } } val iosMain by creating { dependsOn(commonMain) dependencies { implementation("io.ktor:ktor-client-darwin:2.3.7") } } } } |
公式サンプルの Gradle ファイルは常に最新版が公開されています(https://github.com/JetBrains/kotlin/tree/master/samples/multiplatform)。
4. 手動でマルチプロジェクト構成へ移行
4-1 settings.gradle.kts の基本設定
|
1 2 3 4 5 6 7 8 9 10 |
rootProject.name = "my-kmp-multi" include(":shared") include(":androidApp") include(":iosApp") // 必要に応じてディレクトリを明示(可読性向上) project(":androidApp").projectDir = file("androidApp") project(":iosApp").projectDir = file("iosApp") |
階層は :shared → プラットフォームアプリ の順に並べると、依存関係が視覚的に把握しやすくなります。
|
1 2 3 4 5 6 7 8 |
my-kmp-multi/ ├─ shared/ // KMP ライブラリ(pure Kotlin) │ └─ src/... ├─ androidApp/ // Android アプリ(Compose UI 例) │ └─ src/... └─ iosApp/ // iOS アプリ(SwiftUI または Compose Bridge) └─ src/... |
androidApp/build.gradle.kts の依存関係
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
plugins { id("com.android.application") kotlin("android") } android { compileSdk = 34 defaultConfig { applicationId = "com.example.myapp" minSdk = 21 targetSdk = 34 } } dependencies { implementation(project(":shared")) implementation(compose.ui) // Compose Multiplatform UI } |
iosApp/build.gradle.kts(Xcode と連携)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
plugins { kotlin("multiplatform") } kotlin { iosX64(); iosArm64(); iosSimulatorArm64() sourceSets { val iosMain by getting { dependencies { implementation(project(":shared")) // UI は SwiftUI 側で実装。必要なら Kotlin/Native の Bridge ライブラリを追加 } } } } |
4-3 Gradle Kotlin DSL による sourceSets 定義(再掲・拡張)
|
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 43 44 |
plugins { kotlin("multiplatform") } kotlin { android() iosX64(); iosArm64(); iosSimulatorArm64() sourceSets { // ── 共通コード ─────────────────────── val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) implementation("io.ktor:ktor-client-core:2.3.7") testImplementation(kotlin("test")) } } // ── Android 用実装 ───────────────────── val androidMain by getting { dependencies { implementation(kotlin("stdlib")) implementation("io.ktor:ktor-client-okhttp:2.3.7") implementation(compose.ui) // UI が必要ならここで追加 } } // ── iOS 用実装(全アーキテクチャ共通) ─────── val iosMain by creating { dependsOn(commonMain) dependencies { implementation("io.ktor:ktor-client-darwin:2.3.7") } } // 各 iOS ターゲットは iosMain を継承 listOf(iosX64(), iosArm64(), iosSimulatorArm64()).forEach { target -> getByName("${target.name}Main") { dependsOn(iosMain) } } } } |
型安全な DSL により、スペルミスやバージョン不整合のリスクが低減します。IDE の補完機能を活用してください。
5. 実践的拡張と運用
5-1 UI フレームワークの選択肢と導入方法
| フレームワーク | 対応プラットフォーム | 主な利用シーン |
|---|---|---|
| Compose Multiplatform | Android, iOS (UIKit/SwiftUI bridge), Desktop, Web | 同一 Kotlin UI コードで複数デバイスをカバーしたい場合 |
| SwiftUI | iOS / macOS | Apple エコシステム専用の高度な UI が必要なとき |
| Kotlin/JS + React | ブラウザ, Electron デスクトップ | Web フロントエンドチームとの共通化を図りたい場合 |
Compose の最小実装例
|
1 2 3 4 5 6 |
// shared/src/commonMain/kotlin/com/example/ui/App.kt @Composable fun Greeting(name: String) { Text("Hello, $name!", style = MaterialTheme.typography.h4) } |
- Android:
setContent { Greeting("Android") } - iOS:
ComposeViewController.setRootView { Greeting("iOS") }(公式ガイド https://developer.android.com/jetpack/compose/multiplatform)
5-2 期待値テスト (expect/actual) の書き方
|
1 2 3 4 5 |
// shared/src/commonMain/kotlin/com/example/util/Calculator.kt interface Calculator { fun multiply(a: Int, b: Int): Int } |
|
1 2 3 4 5 |
// androidMain/.../Calculator.android.kt actual class DefaultCalculator : Calculator { actual override fun multiply(a: Int, b: Int) = a * b } |
|
1 2 3 4 5 6 |
// iosMain/.../Calculator.ios.kt actual class DefaultCalculator : Calculator { // overflow 対策例 actual override fun multiply(a: Int, b: Int): Int = Math.multiplyExact(a, b) } |
テストコード(commonTest):
|
1 2 3 4 5 6 7 8 9 10 11 12 |
import kotlin.test.Test import kotlin.test.assertEquals class CalculatorTest { private val calc = DefaultCalculator() @Test fun testMultiply() { assertEquals(20, calc.multiply(4, 5)) } } |
Gradle の test タスクで JVM 上の commonTest が走り、プラットフォーム実装が正しく提供されているかを検証できます(テストガイド → https://kotlinlang.org/docs/multiplatform-test-assertions.html)。
5-3 CI/CD:GitHub Actions + Gradle Remote Build Cache
ワークフロー全体像
|
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 43 44 |
name: KMP CI on: push: branches: [ main ] pull_request: jobs: build: runs-on: macos-14 # iOS ビルドに必要 strategy: matrix: os: [ubuntu-latest, macos-14] java-version: [21] # JDK 21 推奨 steps: - uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v3 with: distribution: temurin java-version: ${{ matrix.java-version }} # Gradle キャッシュの永続化(公式推奨) - name: Cache Gradle packages uses: actions/cache@v3 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle.kts') }} restore-keys: gradle-${{ runner.os }} - name: Build and test (JVM/Android) run: ./gradlew clean build --no-daemon # iOS ビルドは macOS のみで実行 - name: Run iOS tests if: runner.os == 'macOS' run: | xcodebuild -workspace iosApp/iosApp.xcworkspace \ -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' test |
- キャッシュ戦略は公式ドキュメント https://github.com/actions/cache に従い、
gradle-wrapper.propertiesのハッシュでキーを生成しています。 - リモート Build Cache(Gradle Enterprise もしくは自前サーバ)を有効にすれば、PR 毎のビルド時間が約30%短縮されます。
5-4 大規模プロジェクト向けモジュール設計ベストプラクティス
- 機能別 KMP モジュール (
:feature:login,:feature:profile…) - プラットフォームアプリモジュール (
:androidApp,:iosApp) がそれらをimplementationで取り込む形にする。
|
1 2 3 4 5 6 7 8 9 |
my-big-kmp/ ├─ :shared // コアロジック ├─ :feature:login // KMP 機能モジュール │ └─ src/... ├─ :feature:profile // 別機能モジュール │ └─ src/... ├─ :androidApp // Android アプリ本体 └─ :iosApp // iOS アプリ本体 |
依存関係例(login モジュール)
|
1 2 3 4 5 |
dependencies { api(project(":shared")) // 他モジュールからも API として公開 implementation(compose.runtime) // UI が必要ならここで追加 } |
- API vs Implementation を明確に分けることで、変更が波及しにくくなり、CI のインクリメンタルビルドが高速化します(Gradle 公式ガイド → https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations)。
6. まとめ
- KMP の本質は「共通ロジックを
commonMainに、差分だけexpect/actualで実装」すること。これによりコード重複と保守コストが大幅に削減されます。 - 開発環境は IntelliJ 2024.2 / Android Studio Flamingo 系列 + Gradle 8.5 + Kotlin 1.9.22 をベースにし、
gradle-wrapper.propertiesとbuild.gradle.ktsでバージョンを固定すれば安定運用が可能です。 - 公式 Wizardは「Zero‑click」スタートアップとして有効活用でき、生成された
shared / androidApp / iosAppの三層構造は KMP の設計パターンそのものです。 - 手動マルチプロジェクト化では
settings.gradle.ktsにサブプロジェクトを列挙し、:sharedを共通モジュールとして切り出すだけで柔軟な拡張が実現できます。 - 実務的拡張として UI フレームワーク選択、expect/actual テスト、GitHub Actions + Build Cache による高速 CI、そして大規模化時のドメイン別モジュール設計を組み合わせれば、エンジニアリング効率と品質が最大化します。
この手順に沿ってプロジェクトを構築すれば、「Kotlin Multiplatform プロジェクト構成 方法」の全体像をゼロから実装でき、即座に本番レベルのマルチプラットフォームアプリ開発へ移行できます。
参考リンク集
- Kotlin Multiplatform 公式ドキュメント:https://kotlinlang.org/docs/multiplatform.html
- IntelliJ IDEA ダウンロードページ(2024.2 系列):https://www.jetbrains.com/idea/download/
- Gradle Release Notes 8.5:https://docs.gradle.org/8.5/release-notes.html
- Kotlin 1.9.22 リリースノート:https://kotlinlang.org/docs/releases.html#release-1922
- KMM Wizard ガイド:https://kotlinlang.org/docs/multiplatform-mobile-setup.html#creating-a-project-with-the-wizard
- GitHub Actions キャッシュ公式:https://github.com/actions/cache
これらを活用しつつ、プロジェクト固有の要件に合わせて微調整してください。