KMP (Kotlin Multiplatform)の導入検討

はじめに
-

本田技研工業でAndroidAutomotiveOS向けのアプリ開発を担当している松村です。
新規アプリを作成するにあたって、マルチデバイスに対応できる拡張性を持たせた構成にしたいという考えから
KMP(Kotlin Multiplatform)の検討をいたしましたので軽く紹介したいと思います。

まず最初に
-
[最近まで使われていたKMM（Kotlin Multiplatform Mobile）という名称は廃止され、
KMP（Kotlin Multiplatform）に名称を統一されました。](https://blog.jetbrains.com/ja/kotlin/2023/08/update-on-the-name-of-kotlin-multiplatform/)

なぜKMPを検討したのか
-
他にもクロスプラットフォーム([Flutter,](https://flutter.dev/) [.NET MAUI](https://dotnet.microsoft.com/en-us/apps/maui),  [ReactNative](https://dotnet.microsoft.com/en-us/apps/mauihttps://reactnative.dev/))などありますが、
弊社の開発対象がAndroidOS、AndroidAutomotiveOS, AndroidAuto、iOS、CarPlayなど車載向けのアプリも含んでおり、それら全ての既存アプリにも適応できるような技術を検討したところKMPに辿り着きました。
また、コンパイルの時点で各プラットフォームのNativeコードに変換してビルドするので、他と比べてパフォーマンスや信頼感があることも理由が大きいです。

KMPのいいところ
-
- Android開発で使われているKotlinでコーディングするので学習コストが低い。
- ビジネスロジックをiOSとAndroid共有できる。
- [Compose Multiplatform](https://www.jetbrains.com/lp/compose-mpp/)**を使えば**iOSとAndroid共有できる。
- Platform固有のAPIも別モジュールで構成できる
- よく使われるライブラリは公式のJ**etBrainsが提供・メンテナンス**
    - HTTP通信([Ktor](https://github.com/ktorio/ktor))
    - シリアライズ([kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization))
    - 非同期処理([Kotlin Coroutines](https://github.com/Kotlin/kotlinx.coroutines))
- 各Platformに共通部をライブラリとして提供しているため、部分的に導入ができる

KMPの懸念点
-
- KMPがベータ版
- ****ビルド時間が気持ち長くなる****
- 発展途上のライブラリが多い

KMPとは
-
- [Kotlin Multiplatform](https://kotlinlang.org/lp/mobile/)の略称
- Androidでよく使われているKotlinをベースにiOS、Android、macOS、Windows、Linux、watchOS などのさまざまなオペレーティング システムで動作できるよう考えられたクロスプラットフォームの仕組みになります。
- 主なユースケースはモバイルプラットフォーム間(iOS とAndroid)でアプリケーションロジックの共有になります。また、[Compose Multiplatform](https://www.jetbrains.com/lp/compose-mpp/)を使用してJetBrainsの宣言型UI(Material Design 3)をiOS、Android、Desktop、Webなどにも共通のデザインで展開できたりもします。
- 現状はベータ版でステーブルでは無いですが、NetflixやAbemaなどでも使用されているような記事も見受けられますので、導入しても問題ないレベルの実績はあるようです。

KMPのビルドの仕組み
-
- Kotlin で書かれた共有コードは、
    - Androidの場合はKotlin/JVMでJVM bytecodeにコンパイルされ、
    - iOSの場合はKotlin/Nativeでnative binariesにコンパイルされます。
        - ***[Kotlin/Native](https://kotlinlang.org/docs/native-overview.html)は***[Kotlin コンパイラー用のLLVM](https://llvm.org/)とKotlin 標準ライブラリのネイティブ実装で構成されており、特定の仮想マシンなしで実行できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127697/570aae7f-4113-adaf-be67-1537568c529f.png)
引用：[what-is-kotlin-native-and-how-does-it-relate-to-kotlin-multiplatform](https://kotlinlang.org/docs/multiplatform-mobile-faq.html#what-is-kotlin-native-and-how-does-it-relate-to-kotlin-multiplatform)

ツリー構造
-
- 大きく３つのモジュールに分ける
- 移行も段階的にモジュール単位で可能
- ツリー
    - appAndroid : Android向けモジュール
        - src/main/java/com/pj/MainActivity
        - src/main/AndroidManifext.xml
    - appiOS : iOS向けモジュール
        - pj/Info.plist
        - pj/ContentView.swift
        - pj/iOSApp.swift
    - shared: プラットフォーム共通モジュール
        - androidMain : Android固有のAPIを使ったロジック
        - iOSMain : iOS固有のAPIを使ったロジック
        - CommonMain : Kotlinの共通のビジネスロジック
            - data：データ
            - domain：ビジネスロジック
            - ui: [Compose Multiplatform](https://www.jetbrains.com/lp/compose-mpp/)を使ってUIも宣言型UI(Material Design 3)に統一する場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127697/81574b39-53c7-2610-1b41-29c4698e0f21.png)
引用：https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/

プラットフォーム固有のAPIとの接続の仕方
-
- Kotlin Multiplatformにはexpect/actualと言う修飾子が用意されています。
    - これはプラットフォーム固有のAPIを利用した処理をビルド後に、適当なターゲットプラットフォームで動かせるようにするアプリケーションのオプションレイヤーになります。
    - expect：プラットフォームごとに実装したい関数やクラスインターフェイスに付与して定義
    - actual：プラットフォーム固有のAPIを使用した処理に付与して実装

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127697/38da44bc-e444-9f6e-6464-69b988e5cb5c.png)
引用：[multiplatform-connect-to-apis](https://kotlinlang.org/docs/multiplatform-connect-to-apis.html)

よく使われるAndroidライブラリのKMPサポートについて
-
|  | KMP Libs | Android Libs |
| --- | --- | --- |
| Http client | Ktor, Ktrofit | Retrofit |
| Dependency Injection | Koin, Koject, kotlin-inject | Hilt Dagger |
| ViewModel | moko-mvvm | Android Lifecycle View Model |
| Navigation | PreCompose | NavigationCompose |
- 通信でよく使われているRetrofitやDIのHilt DaggerはKMPをサポートしていません。
- そのため、既存のプロジェクトをそのままの移植が困難な場合もあります。
- また、KMP自身がアルファ版ということもあり、ほとんどライブラリがステーブルではない状態です
- その他のKMPで使えそうな[ライブラリ一覧](https://kotlinlang.org/docs/multiplatform-mobile-samples.html)はこちら
- KMPの[サンプルコード集](https://kotlinlang.org/docs/multiplatform-mobile-samples.html)はこちら
    - この中でもNotflixが全てKMP共通ライブラリを使用して構成されていています。やろうと思えば全部共通化できちゃう
        
        
        | name | What's shared? | Popular libraries used | UI Framework | Features |
        | --- | --- | --- | --- | --- |
        | Notflix | Models, Networking, Caching, ViewModels | Koin, Ktor, Multiplatform settings, kotlinx.coroutines, kotlinx.serialization, kotlinx.datetime, Napier | Jetpack Compose-Android, Compose Multiplatform-Desktop | Modular architectureRuns on desktopSharing viewmodel |

おわりに
-
KMPはアルファ版ではありますが、ステーブルも近いかなーという印象です。
下名の所属するPJでもロジック周りはKMPで共通化をしてもいいかなと感じました。
また、UIに関してもデザイナー次第ですがComposeMultiplatformで共通化をしてもいいかなとも感じました。
ただ、ライブラリの選定に関しては公式がサポートがない場合やベータ版のようなバージョン状態のものが多いので安易にライブラリの導入は難しいかなと感じました。
まだまだ発展途上なものですが、導入を進めていけたらなと思った次第です。

採用情報
-
本田技研工業に少しでも興味を持っていただきましたら、
お気軽に[エントリー](https://www.honda-jobs.com/job/category/?utm_source=google&utm_medium=cpc&utm_campaign=p-max&gad=1&gclid=CjwKCAjwvfmoBhAwEiwAG2tqzJbzeebvfy8NMytDlz_Gf1jDLJRAPzgSnpWXuIw5RxDpfkbasXXCthoC2mkQAvD_BwE)をお願いします。