酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

KMMライブラリをiOSプロジェクトから利用する

Kotlin Multiplatform Mobile (以下KMM)を使ってアプリを開発したいと考えている。

将来的には Jetpack Compose を使って UI を実装すれば、Flutter のように共通のコードで iOS側でも実行できるようになるようだが現時点では難しそうだ。Android Studio 上で iOSアプリを開発するのも IDE の支援を受けられず厳しい。少なくとも私には無理だ。iOSプロジェクトの開発には Xcode を使いたい。

そこでアプローチを変えることを考えた。そこで Kotlin Multiplatform Mobile Library (以下KMMライブラリ)を使ってビジネスロジックを実装して shared.xcframework を出力する。iOSアプリではその shared.xcframework を import して利用できるかを検証していく。

KMMライブラリのプロジェクトを作成する

スケルトンをそのまま使う。ポチポチしていく。

できました。

KMMライブラリの構造について

KMMライブラリは下図の構造となっている。

.
├── androidMain
│   └── kotlin
│       └── jp
│           └── ch3cooh
│               └── kmmsaple
│                   └── Platform.kt
├── commonMain
│   └── kotlin
│       └── jp
│           └── ch3cooh
│               └── kmmsaple
│                   ├── Greeting.kt
│                   └── Platform.kt
└── iosMain
    └── kotlin
        └── jp
            └── ch3cooh
                └── kmmsaple
                    └── Platform.kt

iOS/Android共通の処理を commonMain に実装して、各プラットフォームごとの処理を androidMain および iosMain に実装する。commonMain で一本化できるのが理想だろうが、このスケルトンライブラリのようにプラットフォームを取得するのに iOS固有の UIDevice を使わないといけなかったりする。

commonMain/Greeting.kt

アプリ側からは Greetingクラスを使うことになる。アプリ側でGreeting().greet() を実行すれば Hello, iOS 16.2! と文字列が返ってくる。

class Greeting {
    private val platform: Platform = getPlatform()

    fun greet(): String {
        return "Hello, ${platform.name}!"
    }
}

commonMain/Platform.kt

Platform は interface である。androidMain と iosMain にてプラットフォーム固有の実装をおこなう。

interface Platform {
    val name: String
}

expect fun getPlatform(): Platform

iosMain/Platform.kt

iosMain/Platform.kt には iOS側の実装を書く。アプリが動いている環境を取得するのに UIDevice を使っているのがわかる。

class IOSPlatform: Platform {
    override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}

actual fun getPlatform(): Platform = IOSPlatform()

KMMライブラリを .xcframework として出力する

Android Studio の Terminal で ./gradlew assembleXCFramework を実行すると、shared.xcframework が出力される。

$ ./gradlew assembleXCFramework

> Task :shared:assembleSharedDebugXCFramework
xcframework successfully written out to: MY_PATH/build/XCFrameworks/debug/shared.xcframework

> Task :shared:assembleSharedReleaseXCFramework
xcframework successfully written out to: MY_PATH/build/XCFrameworks/release/shared.xcframework

iOS プロジェクトから KMM ライブラリを参照する

Xcodeで任意のスケルトンアプリプロジェクトを作成する。

frameworks ディレクトリを作成して、さきほど出力した shared.xcframework をコピーする。

Xcode のプロジェクト設定の Frameworks, Libraries, and Embedded Content から shared.xcframework を参照する。

ViewController.swift

KMMライブラリで生成した文字列をUILabel に表示させる。画面表示時に呼ばれる viewDidLoad() にて Greeting().greet() を実行させる。

import UIKit
import shared

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        label.text = Greeting().greet()
    }
}

iOSプロジェクトから KMMライブラリを利用した結果

Xcode で実行した結果は下図の通り。

まとめ

以上のことから Xcode の iOSプロジェクトから KMMライブラリを利用できることがわかった。Android アプリ + KMMライブラリで先行開発し、あとから iOSアプリを開発するケースでは大いに役立ちそうだ。