Is it possible to use high-order suspend function ...
# multiplatform
p
Is it possible to use high-order suspend function in KMP with iOS target? This is the code in shared:
Copy code
fun initKoinIos(buildEnvironment: BuildEnvironment, getAccessToken: suspend () -> String): KoinApplication =
    initKoin(
        appModules = listOf(),
        buildEnvironment = buildEnvironment,
        getAccessToken = getAccessToken
    )
but it translate to KotlinSuspendFunction in objC/Swift and I have no idea how to use it there. According to https://kotlinlang.org/docs/native-objc-interop.html#mappings it should be async/completionHandler, but I guess it does not work for high order functions?? I am thinking of making an interface with this suspend function, but wanted to ask about your opinion.
c
I tend to avoid trying to implementing suspended functions in kotlin native. Instead I would tend to write an interface that exposes a function with a callback. For example:
Copy code
interface TokenProvider {
	fun getToken(callback: (String) -> Unit)
}
Then pass an implementation of this interface into koin, instead of your higher order function. Then when you need to use this inside a coroutine in your KMP code, wrap the
TokenProvider::getToken
inside a
suspendCancellableCoroutine
. There may be a way to do what your wanting to do, but personally I prefer to abstract away the complexity of coroutines from the underlying platforms.
👍 1
p
the problem is not on KMP side, but iOS. The function that provides the token is async in iOS SDK. I need taht token “on demand” from KMP. It works like that: KMP is making networking calls, whenever network call needs authorization, it calls: getToken. Both platforms (android and iOS) needs to provide that token. On android I am using runBlocking { sdk.getToken() } to get that string, but I do not know equivalent on iOS. That is why I try to make suspend function, so I could use completionHandler
c
> the problem is not on KMP side, but iOS Yup I understand that, and thats what I'm trying to demonstrate above. Let me clarify in more detail: In KMP you declare a public
TokenProvider
interface as detailed above. Then you create iOS and Android implementations of that. The iOS one could look something like this in swift:
Copy code
public final class IosTokenProvider: TokenProvider {
	public func getToken(callback: @escaping (String) -> Void) {
		// Do your async work here then invoke
		// the callback when you have the value you need
	}
}
Then in your KMP code where you need to use this, you do so like here:
Copy code
internal class SharedApi(
    private val client: ApiClient,
    private val tokenProvider: TokenProvider,
) {

    suspend fun fetchData() {
        val token = fetchToken()
        return client.getData(token)
    }
    
    private suspend fun fetchToken(): String {
        return suspendCancellableCoroutine { continuation ->
            tokenProvider.getToken(
                callback = { token -> continuation.resume(token) }
            )
        }
    }
}
The intention here is that we are not exposing the complexity of coroutines to underlying platforms, but just providing an API in which a particular platform can provide a token when the KMP code needs it. In my humble opinion this is a more idiomatic implementation and more enjoyable for iOS devs as they are not having to deal with the headache of integrating coroutines into their iOS codebase