8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kotlin Multiplatformを用いたプロジェクトでiOSアプリをマルチモジュール構成にする

Last updated at Posted at 2024-03-29

はじめに

本田技研工業でiOSアプリ開発を担当している薄田です。
現在、弊社ではモバイルアプリを開発するにあたり、KotlinMultiplatform(以下KMP)の導入を検討しています。
KMPを使えば、Kotlinで書かれたコードを複数のプラットフォーム(iOS/Android/Web等)で共有することができます。これによりロジック実装の重複を避けることができ、開発効率の向上が見込めます。

最近はマルチモジュール構成のiOSプロジェクトをよく見かけるため、KMPプロジェクトでも同様の構成でiOSアプリを作成することができないか気になり調べてみました。
本記事ではKMPプロジェクトでiOSアプリをマルチモジュール構成にする方法を紹介したいと思います。

マルチモジュール構成のメリット

少しだけマルチモジュール構成のメリットに関して触れようと思います。
マルチモジュール構成を採用することで、以下のようなメリットを得ることができます。

  • モジュール単位でビルド可能なため、Xcodeプレビューやテストを実行する際のビルド時間を短縮することができる
  • いくつかのモジュールを組み合わせて機能単体で動くミニアプリを構築できるため、開発サイクルが高速に回せる
  • 機能ごとにモジュールを分割することで、モジュール間の依存関係が明確になる

KMPプロジェクトでマルチモジュール構成にする

KMPプロジェクトの作成

まずはAndroidStudioからKMPプロジェクトを作成します。
このとき、iOS framweork distributionはRegular frameworkを選択してください。
スクリーンショット 2024-03-27 22.26.51.png

iOSプロジェクトを開く

KMPプロジェクトを作成すると、.xcodeprojファイルも自動で生成されます。
/入力したApp名/入力したApp名.xcodeprojにあるため、iosApp名をデフォルトの状態で作成した場合は/iosApp/iosApp.xcodeprojとなります。
このプロジェクトファイルを開いてください。

SwiftPackageの追加

次にSwiftPackageを追加していきます。
ツールバーのFile > New > Package...を選択してください。
スクリーンショット 2024-03-27 22.39.34.png

Libraryを選択し、
スクリーンショット 2024-03-27 22.42.39.png

Add to, Groupには対象のプロジェクトを選択し、作成してください。
スクリーンショット 2024-03-27 22.44.31.png

このような構成になっているかと思います。
スクリーンショット 2024-03-28 0.48.28.png

共有ロジックをXCFramework形式で生成する

KMPでは、Kotlin/Nativeコンパイラが各プラットフォームに合わせてファイルを生成します。iOS向けにはFrameworkが生成されます。これをXcodeプロジェクトに組み込むことで、SwiftコードからKotlinコードを呼び出せるようになっています。
しかしながら、このFrameworkはSwiftPackageManagerで管理することができず、障壁となっていました。
そこで、共有ロジックをXCFrameworkとして生成します。XCFrameworkであればbinaryTargetで対象モジュールに対して依存追加を行うことが可能となります。
XCFrameworkの生成方法はKMP公式サイトで紹介されているので、同様のやり方で生成します。
https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks

まず、XCFrameworkを作成するためにsharedディレクトリのbuild.gradle.ktsを編集します。

build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework

plugins {
    alias(libs.plugins.kotlinMultiplatform)
}

kotlin {
    val xcFramework = XCFramework()
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
            xcFramework.add(this)
        }
    }
}

build.gradle.ktsでXCFrameworkを宣言したことで、gradleに以下3つのタスクが追加されます。

  • assembleReleaseXCFramework
    • /shared/build/XCFrameworks/releaseにRelease用のXCFrameworkを生成
  • assembleDebugXCFramework
    • /shared/build/XCFrameworks/debugにdSYMを含んだXCFrameworkを生成
  • assembleXCFramework
    • Debug用、Release用どちらも生成

上記いずれかのタスクを実行することでXCFrameworkが生成されます。

$ ./gradlew assembleDebugXCFramework

以下のようにコードを修正することでXCFramework名を変更することができます。

kotlin {
    val xcFramework = XCFramework("Hoge") // ココ
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "Hoge" // ココ
            xcFramework.add(this)
        }
    }
}

この変更を加えるとgradleのタスク名も変更されるので注意してください。

  • assembleHogeReleaseXCFramework
  • assembleHogeDebugXCFramework
  • assembleHogeXCFramework

Package.swiftでXCFrameworkを取り込む

作成したXCFrameworkをSwiftPackageManagerでiOSプロジェクトに取り込んでいきます。
XCFrameworkを依存追加する場合は、Package.swiftのtargetsにbinaryTargetを追加します。
先ほど生成したXCFrameworkをpathに指定しましょう。
また、共有ロジックを必要とするモジュールのdependenciesにbinaryTargetを追加しましょう。

Package.swift
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "Modules",
    products: [
        .library(
            name: "Modules",
            targets: ["ModuleA"]),
    ],
    targets: [
        .binaryTarget(name: "shared", path: "../../../shared/build/XCFrameworks/debug/shared.xcframework"),
        .target(
            name: "ModuleA", dependencies: ["shared"]),
        .testTarget(
            name: "ModuleATests",
            dependencies: ["ModuleA"]),
    ]
)

SwiftPackage内で共有ロジックを利用することができるようになりました。

Build Phaseからスクリプトを削除する

iOSプロジェクトのBuild Phaseを見ると、もともとFramework形式で共有する際に必要だったスクリプトが設定されています。こちらは不要となったため削除しましょう。
スクリーンショット 2024-03-27 23.58.36.png
以上の操作でマルチモジュール構成にできたかと思います。
必要なモジュールを追加していってください!

終わりに

KMPプロジェクトであっても、共有ロジックをXCFramework形式で生成することで、マルチモジュール構成のiOSプロジェクトにすることができました。
少しでも参考になれば幸いです。

参考文献

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?