1. 始める前に
前提条件
- Jetpack Compose アプリを構築する方法に関する知識
- Kotlin を使用した経験
- Swift 構文に関する基礎知識。
必要なもの
- Android Studio の最新の安定版(Meerkat 以降)。
- Xcode 16.1 と iPhone シミュレーター(iOS 16.0 以降を搭載したもの)を搭載した macOS システム。
学習内容
- Kotlin マルチプラットフォームの基本を理解する。
- プラットフォーム間でコードを共有する方法。
- Android と iOS で共有コードを接続する方法。
2. セットアップする
バックアップの手順:
- GitHub リポジトリのクローンを作成します。
$ git clone https://github.com/android/codelab-android-kmp.git
または、リポジトリを ZIP ファイルとしてダウンロードすることもできます。
- Android Studio で
get-started
プロジェクトを開きます。このプロジェクトには以下のブランチが含まれます。
main
: このプロジェクトのスターター コードが含まれています。これに変更を加えて Codelab を完了します。end
: この Codelab の解答コードが含まれています。
この Codelab は、main
ブランチから始めます。Codelab の手順に沿って、ご自分のペースで進めることができます。
- 解答コードを確認する場合は、このコマンドを実行します。
$ git clone -b end https://github.com/android/codelab-android-kmp.git
または、解答コードをダウンロードすることもできます。
XCode をインストールします。
この Codelab の iOS 部分をビルドして実行するには、Xcode と iOS シミュレーターが必要です。
- Mac アプリストアから Xcode をインストールします(Apple アカウントが必要です)。
- インストールが完了したら、Xcode を起動します。
- 組み込まれているコンポーネントと、ダウンロードが必要なコンポーネントを示すダイアログが表示されます。
- iOS 18.4(またはより新しいバージョン)を確認します。
- [ダウンロードしてインストール] をクリックします。
- コンポーネントがインストールされるまで待ちます。
この Codelab は Xcode 16.3 でテストされています。他のバージョンの Xcode を使用しているときに問題が発生した場合は、この Codelab で説明されているのと同じバージョンをダウンロードすることをおすすめします。
サンプルアプリ
このコードベースには、Jetpack Compose でビルドされた Android アプリと SwiftUI でビルドされた iOS アプリの両方が含まれています。Android プロジェクトは androidApp/
フォルダに配置されます。iOS プロジェクトは iosApp/
フォルダに配置され、このフォルダには、Xcode で実行する KMPGetStartedCodelab.xcodeproj
も含まれています。
3. Kotlin マルチプラットフォームの概要
Kotlin マルチプラットフォーム(KMP)を使用すると、一度記述したコードを、Android、iOS、ウェブ、パソコンなどの複数のターゲット プラットフォームで共有できます。KMP を活用することで、コードの重複を最小限に抑え、整合性を維持し、開発に要する時間と労力を大幅に削減できます。
KMP では、共有するコードベースの量や部分を判断しません。共有する価値があるコードの部分は、自由に決定できます。
共有する内容を決定する
この共有コードにより、プラットフォーム間で整合性を維持し、重複を低減することができます。多くのモバイルチームは、まず個別のビジネス ロジック(データベース アクセス、ネットワーク アクセスなど)と関連するテストを共有し、その後、追加のコードを共有します。
多くの Android Jetpack ライブラリは KMP をサポートしています。マルチプラットフォーム化された Jetpack ライブラリは、ターゲット プラットフォームに応じて複数のサポート ティアを提供します。ライブラリとそれらのサポートレベルの全一覧については、ドキュメントをご覧ください。
たとえば、サポートされているライブラリの 1 つである Room データベース ライブラリは、Android、iOS、デスクトップのすべてをサポートしています。これにより、両方のプラットフォーム上の他のネイティブ コードを保持しながら、データベースの作成と関連するデータベース ロジックを共通の KMP 共有モジュールに移行できます。
データベースの移行後の次のステップとして、他のドメイン ロジックを共有することもできます。また、Android Jetpack の ViewModel
マルチプラットフォーム ライブラリの使用も検討してください。
プラットフォーム固有のコードを記述する方法
Kotlin マルチプラットフォームでは、プラットフォーム固有の機能を実装する新しい手法が導入されています。
expect 宣言と actual 宣言
expect
actual
Kotlin 言語機能は、IDE をフルサポートする Kotlin マルチプラットフォーム コードベースをサポートするように設計されています。
このアプローチは、プラットフォーム固有の動作を単一の関数またはクラスにカプセル化できる場合に最適です。これは柔軟かつパワフルなメカニズムです。たとえば、共通の expect
クラスには、よりオープンな可視性修飾子、追加のスーパータイプ、異なるパラメータ タイプまたは修飾子を持つ、プラットフォーム固有の actual
の対応クラスを設定できます。厳格なインターフェース API では、このようなバリエーションを実現できません。さらに、expect
actual
は静的に解決されます。つまり、プラットフォーム固有の実装がコンパイル時に適用されます。
Kotlin でのインターフェースと実装
両方のプラットフォームで同様の API に準拠しつつ、実装が異なる必要がある場合は、expect 宣言とactual 宣言の代わりに、共有コードでインターフェースを定義できます。このアプローチにより、異なるテスト実装を使用したり、実行時に別の実装に切り替えたりできます。
また、インターフェースには Kotlin 固有の知識は必要ないため、他の言語のインターフェースに精通しているデベロッパーにも使いやすいオプションです。
共通の共有コードのインターフェース、ネイティブ コード(Android または Swift)の実装。
場合によっては、KMP コードでは利用できないコードを記述する必要があります。この場合は、共有コードでインターフェースを定義し、Android 用に Kotlin で実装して、iOS 用に Swift で対応するインターフェースを用意できます。通常、ネイティブ実装は、依存関係の挿入によって、または直接、共有コードに挿入されます。この戦略により、共有コードの共通インターフェースを維持しながら、各プラットフォームでカスタマイズされたエクスペリエンスを実現できます。
4. Android Studio から Xcode プロジェクトを開く
Xcode をインストールしたら、iOS アプリを実行できることを確認する必要があります。
iOS プロジェクトは Android Studio から直接開くことができます。
- [Project] ペインを切り替えて Project ビューを使用します。
- KmpGetStartedCodelab.xcodeproj フォルダ
で KmpGetStartedCodelab.xcodeproj ファイルを探します。
- ファイルを右クリックし、[開く]、[関連するアプリで開く] を選択します。Xcode で iOS アプリが開きます。
- ⌘+R をクリックするか、[Product] メニューに移動して [Run] を選択して、Xcode でプロジェクトを実行します。
。
5. KMP モジュールを追加する
プロジェクトに KMP サポートを追加するには、まず、プラットフォーム(Android、iOS)間で再利用されるコードの shared
モジュールを作成します。
Android Studio には、KMP 共有モジュール テンプレートを使用して Kotlin マルチプラットフォーム モジュールを追加する方法が用意されています。
KMP モジュールを作成するには、Android Studio で次の操作を行います。
- [File] > [New] > [New Module] > [Kotlin Multiplatform Shared Module] に移動します。
- パッケージを
com.example.kmp.shared
に変更します。 - [Finish]
をクリックします。
- モジュールの作成が完了し、Gradle の同期が完了すると、プロジェクトに新しい
shared
モジュールが表示されます。以下に示すビューを表示するには、[Android] ビューから [Project] ビューに切り替えることが必要な場合があります。
KMP 共有モジュール テンプレートによって生成された共有モジュールには、基本的なプレースホルダ関数とテストが含まれています。これらのプレースホルダにより、モジュールが最初から正常にコンパイルされ、実行されます。
重要: iOSApp フォルダと iOSMain フォルダの違いに注意してください。iOSApp フォルダにはスタンドアロンの iOS アプリコードが含まれていますが、iOSMain は先ほど追加した KMP 共有モジュールの一部です。iOSApp には Swift コードが含まれ、iOSMain には iOS プラットフォーム固有の KMP コードが含まれます。
共有モジュールを Android アプリにリンクする
まず、アプリが共有コードを使用できるように、新しい共有モジュールを :androidApp
Gradle モジュールの依存関係としてリンクする必要があります。
androidApp/build.gradle.kts
ファイルを開きます。- 次のように、依存関係ブロックに
shared
モジュールの依存関係を追加します。
dependencies {
...
implementation(projects.shared)
}
- プロジェクトを Gradle ファイルと同期します。
shared
モジュールへのコードアクセスを確認する
Android アプリが shared
モジュールのコードにアクセスできることを確認するため、アプリの簡単な更新を実施します。
- KMPGetStartedCodelab プロジェクトで、
androidApp/src/main/java/com/example/kmp/getstarted/android/MainActivity.kt
にあるMainActivity
ファイルを開きます。 Text
コンポーザブルのコンテンツを変更して、表示される文字列にplatform()
情報を含めます。
Text(
"Hello ${platform()}",
)
- キーボードの
⌥(option)+return
をクリックし、Import function 'platform'
を選択します。 - Android デバイスまたはエミュレータでアプリをビルドして実行します。
この更新により、アプリが shared
モジュールから platform()
関数を呼び出せるかどうかがチェックされます。この関数は、Android プラットフォームで実行すると、"Android"
を返します。
6. iOS アプリに共有モジュールを設定する
Swift は、Android アプリのように Kotlin モジュールを直接使用できないため、コンパイル済みバイナリ フレームワーク(XCFramework バンドル)を生成する必要があります。XCFramework バンドルは、複数の Apple プラットフォーム向けのビルドに必要なフレームワークとライブラリを含むバイナリ パッケージです。
共有ライブラリの配布方法
Android Studio の新しいモジュール テンプレートでは、各 iOS アーキテクチャのフレームワークを生成するように共有モジュールがすでに設定されています。shared
モジュールの build.gradle.kts
ファイルには以下のコードが表示されます。
val xcfName = "sharedKit"
iosX64 {
binaries.framework {
baseName = xcfName
}
}
iosArm64 {
binaries.framework {
baseName = xcfName
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = xcfName
}
}
iOS プロジェクトで共有ライブラリをリンクする
このステップでは、スクリプトを実行して Kotlin フレームワークを生成するように Xcode を設定し、iOS アプリで platform()
関数を呼び出します。
共有ライブラリを使用するには、次のステップで Kotlin フレームワークを iOS プロジェクトに接続する必要があります。
- Xcode で iOS プロジェクト(前述の
iosApp
ディレクトリ)を開き、プロジェクト ナビゲータでプロジェクト名をダブルクリックしてプロジェクト設定を開きます。 - プロジェクト設定の [ビルドフェーズ] タブで、+ をクリックして [新しいスクリプトの実行フェーズ] を選択します。これにより、他のすべてのフェーズの後ろに新しい「スクリプトの実行」フェーズが追加されます。
- [スクリプトの実行] のタイトルをダブルクリックして名称を変更します。このフェーズの内容を明確にするために、デフォルトの [スクリプトの実行] の名称を [Kotlin フレームワークのコンパイル] に変更します。
- ビルドフェーズを開き、[Shell] の下のテキスト フィールドに次のスクリプト コードを入力します。
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode
- [ Kotlin フレームワークのコンパイル] フェーズを [ソースのコンパイル] フェーズの前にドラッグします。
- ⌘+B をクリックするか、[Product] メニューに移動して [ビルド] を選択し、Xcode でプロジェクトをビルドします。ビルドの進行状況は Xcode の上に表示されます。
すべてが正しく設定されていれば、プロジェクトは正常にビルドされます。
このようにスクリプトの実行 ビルドフェーズを設定すると、共有モジュールをコンパイルするために別のツールに切り替えることなく、Xcode から iOS プロジェクトをコンパイルできます。
shared
モジュールへのコードアクセスを確認する
iOS アプリが shared
モジュールのコードに正常にアクセスできることを確認するには、Android アプリに対して行った簡単な更新を iOS アプリに対して行います。
- Xcode の iOS プロジェクトで、
Sources/View/ContentView.swift
にあるContentView.swift
ファイルを開きます。 - ファイルの先頭に
import sharedKit
を追加します。 Text
ビューを変更して、表示される文字列にPlatform_iosKt.platform()
情報を\(Platform_iosKt.platform())
で配置します。
ファイルの最終的な結果は次のようになります。
import SwiftUI
import sharedKit
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, \(Platform_iosKt.platform())!")
}
.padding()
}
}
- ⌘+R をクリックするか、[Product] メニューに移動して [Run] をクリックしアプリを実行します。
この更新により、iOS アプリが共有モジュールから platform()
関数を呼び出せるかどうかがチェックされます。この関数は、iOS プラットフォームで実行すると、"iOS"
を返します。
7. Swift/Kotlin Interface Enhancer(SKIE)を追加
デフォルトでは、Kotlin が生成したネイティブ インターフェースは Objective-C ヘッダーです。Swift は Objective-C と直接互換性がありますが、Objective-C には Swift や Kotlin の最新機能がすべて含まれているわけではありません。
これは、前の例で Swift コード内で platform()
呼び出しを直接使用できなかった理由でもあります。Objective-C はグローバル関数をサポートしておらず、クラスにカプセル化された静的関数のみをサポートしているため、KMP はグローバル関数を生成できません。そのため、Platform_iosKt
を追加する必要があります。
インターフェースを Swift に適したものにするには、Swift/Kotlin Interface Enhancer(SKIE)ツールを使用して、:shared
モジュールの Swift インターフェースを改善します。
SKIE の一般的な機能は次のとおりです。
- デフォルト引数のサポートを強化
- sealed 階層のサポートを強化(
sealed class
、sealed interface
) switch
ステートメントでの網羅的な処理を備えたenum class
のサポートの改善Flow
とAsyncSequence
の互換性suspend fun
とasync func
の互換性
co.touchlab.skie
Gradle プラグインをlibs.versions.toml
ファイルに追加します。
[versions]
skie = "0.10.1"
[plugins]
skie = { id = "co.touchlab.skie", version.ref = "skie" }
- プラグインをルートの
build.gradle.kts
ファイルに追加する
plugins {
...
alias(libs.plugins.skie) apply false
}
- プラグインを
:shared
モジュールのbuild.gradle.kts
ファイルに追加します。
plugins {
...
alias(libs.plugins.skie)
}
- プロジェクトを Gradle 同期します。
静的関数呼び出しを削除する
iOS アプリを再ビルドしてもすぐには何も変化しない可能性がありますが、Platform_iosKt
接頭辞を削除して、platform()
関数をグローバル関数として機能させることができます。
Text("Hello, KMP! \(platform())")
これは、SKIE が(他の機能とともに)Swift の API Notesを活用しているためです。API Notes は、Swift コードから API をより適切に使用できるように、API に関する情報を追加します。
8. 完了
お疲れさまでした。これで、Android プロジェクトと iOS プロジェクトに最初の共有 Kotlin マルチプラットフォーム コードが追加されました。これは最小限の開始点にすぎませんが、これで KMP でコードを共有するための高度な機能とユースケースを探求できるようになりました。
次のステップ
次の codelab では、Jetpack Room を使用して Android と iOS 間でデータレイヤを共有することについて学びます。
詳細
- KMP をサポートする Jetpack ライブラリについて学習する
- 公式の Kotlin マルチプラットフォーム ドキュメントを確認する