0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KMPのマルチモジュール構成では、StaticなiOSフレームワークは1つに集約すべきっぽい

Posted at

この記事は、筆者のメモを基に、AIが構成・加筆を行ったものです。

KMPのプロジェクトで複数のモジュールを作成し、それぞれをiOS側で使えるようにしていました。build-logicを以下のように作成して、複数のモジュールから参照していたのですが、Skieを導入したタイミングで問題が発生しました。

import co.touchlab.skie.plugin.configuration.skieExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

open class KmpPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            plugins.apply("org.jetbrains.kotlin.multiplatform")
            plugins.apply("com.android.library")
            plugins.apply("co.touchlab.skie")
            extensions.getByType(KotlinMultiplatformExtension::class).apply {
                androidTarget {
                    compilerOptions {
                        jvmTarget.set(JvmTarget.JVM_21)
                    }
                }

                listOf(
                    iosX64(),
                    iosArm64(),
                    iosSimulatorArm64(),
                ).forEach { iosTarget ->
                    iosTarget.binaries.framework {
                        baseName = "iOSKmp${project.name}"
                        isStatic = true
                    }
                }

                sourceSets.apply {
                    commonMain.dependencies {
                    }
                    commonTest.dependencies {
                        implementation(libs.findLibrary("kotlin-test").get())
                    }
                }
            }
            configureAndroidLibrary(this)
            skieExtension.apply {
                features {
                    enableSwiftUIObservingPreview.set(true)
                }
            }
        }
    }
}

アプリを実行すると、以下のようなエラーが発生しました:

objc[501]: Class IOSKSkieColdFlowIterator is implemented in both /private/var/containers/Bundle/Application/9E7BBDB1-E633-463F-AA33-552FFFAE156B/KotlinProject.app/KotlinProject.debug.dylib (0x10b479e30) and /private/var/containers/Bundle/Application/9E7BBDB1-E633-463F-AA33-552FFFAE156B/KotlinProject.app/KotlinProject.debug.dylib (0x10b479e30). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[501]: Class IOSKSkieKotlinFlow is implemented in both
...

どうやら、複数のモジュールからそれぞれStaticなフレームワークを生成していることが原因のよう。

Kotlinの公式ドキュメントを確認してみると、実はこの問題について言及されていました:

For example, you implement several modules in Kotlin and want to access them from Swift. Usage of several Kotlin/Native frameworks in a Swift application is limited, but you can create an umbrella framework and export all these modules to it.

つまり、複数のKotlinモジュールをSwiftから利用する場合は、「アンブレラフレームワーク」として1つにまとめるべきということです。

試したこと

1. キャッシュを無効にする

まず、以下の設定を試してみました:

kotlin.native.cacheKind=none

これはYouTrackのissue(https://youtrack.jetbrains.com/issue/KT-42254)で提案されていた方法ですが、残念ながら私の環境では解決しませんでした。また、この方法はパフォーマンスにも悪影響があるようです。

2. 動的フレームワークに変更する

次に、静的フレームワークではなく動的フレームワークを使用する方法を検討しました:

isStatic = false

これは動作する可能性がありますが、アプリ申請時にはXcodeのBuild Phasesで「Embed & Sign」を正しく設定する必要があり、別の問題が発生する可能性があります。

3. アンブレラフレームワークを作成する(推奨解決策)

最終的に採用したのは、iOS用のエントリーポイントとなる専用モジュールを1つ作成し、そこから必要なモジュールをエクスポートする方法です。

以下のようにios-umbrellaモジュールを作成しました:

plugins {
    id("composit.build.kmp")
} 

kotlin {
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64(),
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "SharedIOSFramework"
            isStatic = true
        }
    }

    sourceSets.commonMain.dependencies {
        api(projects.domain)
        api(projects.common)
        // 他の必要なモジュール
    }
}

この方法で、iOS側に公開するフレームワークを1つにまとめることができました。

注意点

  • commonMainにKotlinソースがないとコンパイラが反応しないため、ダミーの.ktファイルも必要です
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?