Andrew Watson
04/23/2024, 5:22 PMkpgalligan
04/23/2024, 9:24 PMHey all, I figure there are articles that cover this, but I've got a KMP multi-module project, and I want to expose one of the modules to the Swift app for configuration.Are you current exporting anything to Swift, or is this the first export to Swift from your KMP project?
So I assume I need to make that particular module a swift package and consume in the iosApp "parent"That is one option. It wouldn't be a "swift package" exactly, although you could use SPM to handle the integration with Xcode.
which will enable me to call any interop methods. Is this what I would use KMMBridge for?"interop" is a term used for multiple things in KMP, so to clarify, by "interop" you mean that this would allow Swift to call your KMP methods?
Andrew Watson
04/23/2024, 9:32 PMkpgalligan
04/23/2024, 9:59 PMDoes that make sense? Does that help make clear what I need to do?Somewhat. If you're already using KMP from your iOS app through a Framework, then adding another Framework won't work. You can have 2 KMP Frameworks in 1 iOS, but they are different at a binary level, and classes from one won't be recognized by the other. Options are: • export the business logic module in the main Framework build. Not necessarily a great idea. • Create a factory function in the main KMP/iOS module that can return an instance of the business logic class. That will export just what you need. From this sample you can see different forms of exporting module code. The
allshared
module is the "umbrella" module exporting the Xcode framework. There are 2 KMP modules with code. analytics
is intended to be called directly from the Android and iOS apps, so it is exported to the framework. The breeds
module is mostly logic, with a handful of things that Swift actually needs to know about. That module isn't exported, but the allshared
module has code that references the breeds
module, and that is available to Swift.
kotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
export(project(":analytics"))
isStatic = true
}
}
sourceSets {
commonMain.dependencies {
implementation(project(":breeds"))
api(project(":analytics"))
}
}
}
This class is the entry point for iOS, which is used to provide needed init config, and returns various accessors that Swift can interact with.
https://github.com/touchlab/KMMBridgeSKIETemplate/blob/main/allshared/src/iosMain/kotlin/co.touchlab/kmmbridgekickstart/StartSDK.ktAndrew Watson
04/23/2024, 10:02 PMkpgalligan
04/23/2024, 10:04 PMAndrew Watson
04/23/2024, 10:07 PMalllshared
:
it.binaries.framework {
export(project(":analytics"))
isStatic = true
}
Plus KMMBridge is what makes analytics consumable by swift?kpgalligan
04/23/2024, 10:09 PMAndrew Watson
04/23/2024, 10:09 PMkpgalligan
04/23/2024, 10:11 PMit.binaries.framework {
export(project(":analytics"))
isStatic = true
}
This is standard KMP config. It has nothing to do with KMMBridge directly, although it does configure the Framework which KMMBridge can publish. The Kotlin compiler will create an Xcode Framework with whatever API surface is visible from the module that is creating the Framework. If you want other modules to be included entirely, export them. However, it's best to be conservative with the API that is exported to Swift for a number of reasons.Andrew Watson
04/23/2024, 10:16 PMlistOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "Analytics"
isStatic = true
}
}
If I'm reading that example correctly, I don't need that in every module for standard KMP development. But if I need to access Kotlin code originating in descendent modules in Swift I just need to use export(project(":some_module"))
, right?Andrew Watson
04/23/2024, 10:17 PMbaseName
for every modulekpgalligan
04/23/2024, 11:48 PMlistOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
)
Framework module:
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "Umbrella (or whatever)"
isStatic = true
}
}
Andrew Watson
04/23/2024, 11:49 PMkpgalligan
04/23/2024, 11:50 PMkotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
export(project(":analytics"))
isStatic = true
}
}
// Etc
One of the dependent modules.
kotlin {
androidTarget {
publishAllLibraryVariants()
}
iosX64()
iosArm64()
iosSimulatorArm64()
// Etc
Andrew Watson
04/23/2024, 11:51 PM