kotlinkotlin-multiplatform

Unable to resolve cinterop IOS import in Kotlin Multiplatform


I have followed the Kotlin documentation for adding iOS dependencies. In my case the dependency is a pre-compiled framework provided through a third party. So I have followed the case for framework without cocoapod.

I placed my MyFramework.def file in /src

language = Objective-C
modules = MyFramework
package = MyFramework

Then I added the following to the build.gradle.kts in the Kotlin object ```

ios {
    binaries {
        framework {
            baseName = "shared"
        }
    }
}
iosArm64() {
    compilations.getByName("main") {
        val JWBLe by cinterops.creating {
            // Path to .def file
            defFile("src/nativeInterop/cinterop/MyFramework.def")

            compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
        }
    }

    binaries.all {
        // Tell the linker where the framework is located.
        linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
    }
}
sourceSets {
    val commonMain by getting
    val commonTest by getting {
        dependencies {
            implementation(kotlin("test-common"))
            implementation(kotlin("test-annotations-common"))
        }
    }
    val androidMain by getting {
        dependencies {
            implementation("com.google.android.material:material:1.2.1")
        }
    }
    val androidTest by getting {
        dependencies {
            implementation(kotlin("test-junit"))
            implementation("junit:junit:4.13")
        }
    }
    val iosMain by getting
    val iosTest by getting
}

Then I build the project. The library does indeed get seen and I see that in External Libraries, there is a shared-cinterop-MyFramework.klib

However, when I try to import this package into my code under src/iosMain/kotlin/com.example.testapp.shared/platform.kt I get unresolved error for the library. It seems like I should also need to add something to sourceSets? But I am unsure.


Solution

  • First of all, I got to notice that the Gradle script is incorrect. In this case, the iosArm64 target was declared twice - by the target shortcut and once again where you configure the cinterop. To avoid this duplication, it would be better to configure cinterop like that:

    ios()
        val iosArm = targets.getByName("iosArm64") as  org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
        // A bit dirty cast, but as I'm sure iosArm64 is the Native target, it should be fine. Needed to make highlighting below work as expected.
        iosArm.apply {
            compilations.getByName("main") {
                val JWBLe by cinterops.creating {
                    // Path to .def file
                    defFile("src/nativeInterop/cinterop/MyFramework.def")
    
                    compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
                }
            }
            binaries.all {
                // Tell the linker where the framework is located.
                linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
            }
        }
    

    However, this adjustment won't help with accessing cinterop bindings from the iosMain. In the current state of commonizer, it can share only platform libraries. So anyway, moving all code utilizing those bindings into the src/iosArm64Main folder is the best option available at the moment. Here go an issue from the official tracker to upvote and subscribe - Support commonization of user-defined libraries.