Reputation: 604
I'm trying to make a Kotlin Multiplatform library to be used in both Android, JavaScript and iOS. This library is composed of multiple modules so that it can be easily extensible. My problem right now is only with Kotlin native.
:common
object MySingleton {
fun doSomethingWithMyInterface(value: MyInterface) {
// ...
}
}
interface MyInterface {
fun doSomething()
}
MyInterface
class MyInterfaceExample : MyInterface {
override fun doSomething() {
// ...
}
}
I have setup the build.gradle.kts
file for :common
as follow:
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
id("maven-publish")
}
kotlin {
targets {
jvm()
js().browser()
ios("ios") {
binaries {
framework("CommonModule") {
baseName = "common"
}
}
}
}
cocoapods {
frameworkName = "CommonModule"
summary = "My common module"
homepage = "-"
license = "-"
ios.deploymentTarget = "10.0"
}
sourceSets {
val iosX64Main by getting
val iosArm64Main by getting
val iosMain by getting {
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
}
}
}
And my other module as follow:
plugins {
id("com.android.library")
id("maven-publish")
kotlin("multiplatform")
kotlin("native.cocoapods")
}
android {
compileSdkVersion(30)
}
kotlin {
targets {
js().browser()
ios("ios") {
binaries {
framework("ExampleImplementation", listOf(DEBUG)) {
baseName = "example"
freeCompilerArgs += "-Xobjc-generics"
export(project(":common")) {
isStatic = true
}
}
}
}
android("android") {
publishLibraryVariants("release")
}
}
cocoapods {
frameworkName = "ExampleImplementation"
summary = "Example implementation of MyInterface"
homepage = "-"
license = "-"
useLibraries()
ios.deploymentTarget = "10.0"
pod("MyDependency")
}
sourceSets {
val commonMain by getting {
dependencies {
api(project(":common"))
}
}
val iosX64Main by getting
val iosArm64Main by getting
val iosMain by getting {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
}
val androidMain by getting {
dependsOn(commonMain)
dependencies {
implementation("group:artifactId:1.0.0")
}
}
val jsMain by getting {
dependencies {
implementation(npm("my_dependency", "1.0.0"))
}
}
}
}
Both :common
and :example
modules generate a podspec
file which adds a script to be executed by cocoapods manager:
<<-SCRIPT
set -ev
REPO_ROOT="$PODS_TARGET_SRCROOT"
"$REPO_ROOT/../gradlew" -p "$REPO_ROOT" :example:syncFramework \
-Pkotlin.native.cocoapods.target=$KOTLIN_TARGET \
-Pkotlin.native.cocoapods.configuration=$CONFIGURATION \
-Pkotlin.native.cocoapods.cflags="$OTHER_CFLAGS" \
-Pkotlin.native.cocoapods.paths.headers="$HEADER_SEARCH_PATHS" \
-Pkotlin.native.cocoapods.paths.frameworks="$FRAMEWORK_SEARCH_PATHS"
SCRIPT
When I add those modules in an iOS project like so:
pod 'common', :path => '~/Project/MyLibrary/common/'
pod 'example', :path => '~/Project/MyLibrary/example/'
After I do a pod install
, I can see both frameworks being added.
The framework generated for example
doesn't depend on the framework generated for common
. Yet, :example
generates an interface of its own called ExampleCommonMyInterface
which have the same signature as MyInterface
in :common
.
Also, both of them includes some KotlinBase
classes which prevents me from building as I encounter an issue for duplicated classes.
I tried to only include :example
but then it's missing my MySingleton
class (which is not a Singleton in Swift but that's another issue) and other classes which :example
doesn't depend on directly.
Also, at some point, I would like to have more than one module depending on :common
so only including :example
would only work temporarily.
I have tried many things for several days now but none of them works. Also, the documentation is scattered between the documentation for kotlin multiplatform and kotlin native which made it hard for me to find relevant information regarding what I'm trying to achieve.
I understand that Kotlin multiplatform is still not stable and what I'm trying to achieve may not be possible at the moment. Nevertheless, I would greatly appreciate if someone can shed some light on what the problem is and how I can solve it.
Upvotes: 8
Views: 5658
Reputation: 700
At the moment (Kotlin 1.5-M1), Kotlin/Native does not support generating binary frameworks where one depends on another. There are only two working configurations supported right now:
If you are planning to organize your code into a hierarchy of Kotlin modules, (2) is your only option. You either:
example
module, whose framework product already contains all the code of all its dependencies (incling the transitive ones and the Kotlin runtime), as you might have observed; oriosExport
module that exports all the modules that should be API visible to your iOS codebase.The issue tracking improvements in this area: https://youtrack.jetbrains.com/issue/KT-42247
This topic has been briefly touched on by the official KMM documentation:
https://kotlinlang.org/docs/mpp-build-native-binaries.html#export-dependencies-to-binaries [...] For example, assume that you write several modules in Kotlin and then want to access them from Swift. Since usage of several Kotlin/Native frameworks in one Swift application is limited, you can create a single umbrella framework and export all these modules to it.
Upvotes: 12