本田技研工業でAndroidアプリ開発を担当している須藤です。
Kotlin Multiplatform(以下KMP)の新規プロジェクトを作る方法はよく見かけますが、既存のAndroidプロジェクトをKMP化する方法がわからなかったので調べてみました。
手順はJetBrainsの「Make your Android application work on iOS – tutorial」を参考に、自分用の備忘的な意味も兼ねてかなり最低限に絞ってまとめています。
詳細は上記をみていただくのがよいと思いますが、あまり時間がない中でざっくりとした手順を知りたい方や、KMPに馴染みがなく導入のイメージを掴みたい方の手助けになれば幸いです!
目次
- Wizardを使ってKotlin Multiplatform Sharedモジュールを追加する
- 必要なGradle記述を適宜追加する
- 共有したいロジックをSharedモジュール内に移動する
- プロジェクトルートにiOSプロジェクトを追加する
- SharedモジュールをiOSで使えるようにするためのビルド設定を追加する
- iOS側のコードにKMPモジュールの参照箇所を実装する
KMPの概要についてはこちらの記事もおすすめです
1.Wizardを使ってKotlin Multiplatform Sharedモジュールを追加する
まずは、既存のAndroidプロジェクト内に、共有ロジックを配置するためのSharedモジュールを追加していきます。
このSharedモジュールは、AndroidStudioのAdvanced Settingsから「Enable experimental Multiplatform IDE」の設定をONにすることでWizardを使って簡単に追加できるようになります。
下図のようにCreate New Module時に「Kotlin Multiplatform Shared Module」という項目を選択できるようになります。
モジュールを追加すると、
- Sharedモジュール用のbuild.gradle
- SharedモジュールのSourceSetで使用するディレクトリ構成(androidMain/commonMain/iosMain)
- 親プロジェクトからモジュールを参照できるようにするためのsetting.gradleのinclude記述
- 簡単なサンプルコード
などを追加してくれます。
2.必要なGradle記述を適宜追加する
上記のWizardで完全に設定を整えてくれるわけではなく、幾つかの追加記述が必要でした。
現時点では以下の記述を行いましたが、変更される可能性も十分あると思うので、適宜リファレンスを参考にしていただけるとよいと思います。
1.プロジェクトレベルのbuild.gradleにplugin記述を追加する
- Kotlin Multiplatformを使えるようにするためのプラグイン(org.jetbrains.kotlin.multiplatform)
- モジュールをプロジェクトで使えるようにするためのAndroidライブラリプラグイン(com.android.library)
をプロジェクトに適用します。
前者はKotlinバージョン、後者はAGPのバージョンと合わせます。
Kotlinバージョンは1.9.20-2.0.20である必要があります。
サンプルコードは以下です。
plugins {
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.androidLibrary) apply false
...
}
[versions]
agp = "8.2.2"
kotlin = "2.0.0"
...
[plugins]
androidLibrary = { id = "com.android.library", version.ref = "agp" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
...
2.appモジュールのbuild.gradleにsharedモジュールを読み込むための記述を追加する
通常のモジュール同様、親となるappモジュールのbuild.gradleにdependenciesの定義を追加します。
dependencies {
implementation (project(":shared"))
...
}
3.共有したいロジックをSharedモジュール内に移動する
KMPで共有ロジックを実装するshared/commonMainソースセットではJavaに依存するコードが使えません。
そのため、恐らくほとんどのケースではAndroidプロジェクト内の共有したいロジックをそのままcommonMainに移しただけではエラーになってしまうと思います。
これらの処理をKMPでも使える記述に修正していく必要があります。
本家のチュートリアルは簡単なログイン画面を移行するシナリオになっているのですが、ここでは以下のような修正例が紹介されていました。
- ログイン時のエラーハンドリングにIOExceptionを使用していたが、Kotlin JVM環境だと使えないのでRuntimeExceptionに修正する
- メールのバリデーションにandroid.utilsのmatcher関数を使っていたが、Kotlin JVM環境だと使えないのでKotlinのmatches関数に書き換える
(android.utilsと違ってメールアドレス用の正規表現は用意されていないので自分で定数定義する) - ユーザIDの発行にjava.util.UUIDのrandomUUID関数を使っていたがiOSだと使えないのでPlatformごとの実装(actual/expected)を行う
- androidMainではそのままjava.util.UUIDクラスを使用し、iosMainではiOS用のplatform.Foundation.NSUUIDを使用する。
正直ここだけ聞くと、エラーの具体性を落としたり、車輪の再発明的な自前実装部分を増やしたりで微妙に見えるかもしれないですが、最近はKMP対応のライブラリもたくさん出てきているので既存の実装をあまり大きく変えずに移行できるケースもあると思います。
Kotlin Multiplatformでの実装の詳細については以下のチュートリアルをご参照ください。
4.プロジェクトルートにiOSプロジェクトを追加する
iOSプロジェクトがまだない場合は、XcodeでiOSプロジェクトを新規作成する際に、作成先ディレクトリにプロジェクトのルートを指定します。
5.SharedモジュールをiOSで使えるようにするためのビルド設定を追加する
Sharedモジュールの実装をiOSプロジェクトで使えるようにするための設定を行います。
iOSではXcodeのBuild Phasesというメニューでビルド時に実行するスクリプトやタイミングを指定できます。
ここで「Compile Sources」フェーズの前に「Run Script」フェーズを追加し、以下のスクリプトを実行するように設定します。
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode
プロジェクトのルートディレクトリに移動して、フレームワークをXcode用に組み込むGradleコマンドをたたいているようですね。
embedAndSignAppleFrameworkForXcode - Embed and sign framework as requested by Xcode's environment variables
合わせて、スクリプトの実行を許可するために、Build Settingのメニューで「User Script Sandboxing」の項目を無効にします。
上記の設定だとマルチモジュール構成のiOSプロジェクトのパッケージ内からはKMPコードにアクセスすることができません。
iOSプロジェクトをマルチモジュール構成にする場合や、既存のマルチモジュール構成のiOSプロジェクトを使用したい場合は以下の方法を参考にしてください。
6.iOS側のコードにKMPモジュールの参照箇所を実装する
上記の設定後にビルドすることでiOSプロジェクト内でsharedモジュールをimportできるようになります。
これでiOSプロジェクトからKMPモジュールにある実装を参照することができるようになります。
終わりに
ここまで読んでいただきありがとうございました。
少しでもどなたかの参考になれば幸いです。