Quick Way to Run Swift Inside KMP Without Writing Bindings
There are times when you need to run some Swift code inside a Kotlin Multiplatform project but writing bindings for it or adding a plugin that does that just seems too much. I’ve found that defining an interface inside Kotlin and providing its implementation inside Swift is a good solution in such situations.
First, create the interface and define any functions that should be ran inside Swift.
interface SwiftInteropHelper {
fun getVariableFont(width: Double, weight: Double, size: Double): UIFont
}
Then, create a CompositionLocalProvider
so the interface can be easily accessed anywhere. The MainViewController
will now give an instance of it that will be created in Swift.
val LocalSwiftInteropHelper = staticCompositionLocalOf<SwiftInteropHelper> {
error("No swift interop helper provided")
}
fun MainViewController(
swiftInteropHelper: SwiftInteropHelper
) = ComposeUIViewController {
// Make the view factory globally accessible
CompositionLocalProvider(LocalSwiftInteropHelper provides swiftInteropHelper) {
Main()
}
}
Now implement the interface, make sure to import ComposeApp
and first build the gradle project inside Android Studio so Xcode can see the interface. Also create a shared instance of it that will be passed to MainViewController
.
import Foundation
import UIKit
import ComposeApp
class SwiftInteropHelperImpl: SwiftInteropHelper {
static var shared = SwiftInteropHelperImpl()
func getVariableFont(width: Double, weight: Double, size: Double) -> UIFont {
return ...
}
}
Pass the instance to MainViewController
.
struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController(
swiftInteropHelper: SwiftInteropHelperImpl.shared
)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
And that’s it, after the initial setup it’s very easy to add new functions if the need comes.