I have a KMM project with CMP where i want to prov...
# multiplatform
z
I have a KMM project with CMP where i want to provide shared UI to an app that consumes an Android SDK and an iOS SDK (they are native since they handle system sensors and such), their API surface is the same, I am trying to access a class
OSTUserAttributes
in the iosMain folder, however that class seems to be unavailable. I have created a wrapper for that class.
Copy code
import Foundation
import OSTSDK // Import the SDK containing OSTUserAttributes

@objc public class KmmUserAttributes: NSObject {
    private var builder: OSTUserAttributes.Builder
    private var userAttributes: OSTUserAttributes?
    
    public override init() {
        self.builder = OSTUserAttributes.Builder()
        super.init()
    }
    
    @objc public func setFirstName(_ name: String) {
        builder = builder.withFirstName(name)
    }
}
And created a bridging header
iosApp/iosApp-Bridging-Header.h
Copy code
#import "iosApp-Swift.h"
#import "KmmUserAttributes.h"
I cleaned, i built, but whatever i do i have not managed to access
KmmUserAttributes
in iosMain Is there any other approach for accessing swift files from iosApp in iosMain?
m
My normal approach to this is not to access anything Swift from Kotlin (otherwise you have build dependencies in both directions). Instead, I do it all the other way around (calling Kotlin from Swift is super easy). So for example, I'd set up my Kotlin code like this:
Copy code
interface SwiftKotlinBridge {
    fun constructKmmUserAttributes() : KmmUserAttributes
    // Whatever other Swift APIs you want to call from Kotlin would go here

    companion object {
        val INSTANCE get() = swiftKotlinBridgeInstance ?: throw IllegalStateException()
    }
}

private var swiftKotlinBridgeInstance : SwiftKotlinBridge? = null

fun registerSwiftKotlinBridge( instance: SwiftKotlinBridge ) {
    swiftKotlinBridgeInstance = instance
}

interface KmmUserAttributes {
    fun setFirstName( name: String )
}

// It's a function that looks like a constructor
// you could even move the interface to common code
// and make the "constructor" function expect/actual
fun KmmUserAttributes() = SwiftKotlinBridge.INSTANCE.constructKmmUserAttributes()
And then in my Swift code, I just make a class that implements the
SwiftKotlinBridge
and on launch (before any KMM or CMP code is executed) I just call
registerSwiftKotlinBridge()
from the Swift side.
y
The Kotlin compiler doesn't know anything about that file. If you are using cocoapods, you can potentially wrap your
KmmUserAttributes
class in its own pod and declare it as a dependency for your KMP module. This will allow the compiler to link it and will generate the kotlin code to access it.
z
I am using swift package manager. What would be the best practice in this case? A iOS swift packge (native iOS SDK) which exposes classes i want to access in common code?
y
With SPM, you would have to do the linking yourself. The Kotlin compiler needs to get the definition for your framework to be able to generate the Kotlin code. Importing Swift/Objective-C libraries to Kotlin in the docs has couple of helpful links. Cocoapods plugin makes life easier in this regard and you can mix both pods and SPM in the same project.