I’ve written in previous posts about different approaches to consuming, from Swift code, suspend functions and Flows exposed from Kotlin Multiplatform shared code. Kotlin 1.4 added the capability to call suspend functions from Swift/Objective-C (with a number of caveats) and a variety of custom approaches have been used to map from Kotlin Flows to, for example, likes of Swift Combine publishers etc. Swift 5.5 added a number of interesting concurrency capabilities, in particular async/await and AsyncStream, that on the surface would seem to map quite nicely to Kotlin suspend functions and Flows. Initially these were limited to running on iOS 15 but with recent XCode 13.2 beta it’s now possible to use back to iOS 13 etc. In this post I’m going to outline exploration done to use the KMP-NativeCoroutines library to provide this mapping.
KMP-NativeCoroutines is described as “a library to use Kotlin Coroutines from Swift code in KMP apps”. Along with new Swift 5.5 concurrency capabilities it also supports mapping to RxSwift and Combine and critically addresses 2 key areas
- cancellation support
- allow use of generic value type for Flows
Updating BikeShare KMM sample
For the purposes of this exploration I made changes to the BikeShare KMM sample.
The first step is to add following to the
plugins section of
build.gradle.kts for common code.
For this particular project we’re using CocoaPods so we updated
Podfile as follows and then re-ran
pod install. Note that
the library now also supports use of Swift Packages.
The following is excerpt from
CityBikesRepository. We added use of
@NativeCoroutineScope to allow us to specify the coroutine
scope we want to use for requests from iOS code. The plugin will automatically generate
pollNetworkUpdatesNative wrappers respectively for the
fetchNetworkList suspend function and
that returns a
The following is our Swift View Model. We import
KMPNativeCoroutinesAsync and can now make use of
await asyncResult to invoke
fetchNetworkListNative suspend function. For the
pollNetworkUpdatesNative function that returns
Flow we can use
asyncStream. Note also in this case that we store reference to associated
Task and can use that in our
SwiftUI code to trigger cancellation at appropriate time.
This is excerpt of SwiftUI code showing us starting/stopping observation of the bike network updates from
And finally this is screenshot from the iOS app.
Featured in Kotlin Weekly Issue #275
Bridging the gap between Swift 5.5 concurrency and Kotlin Coroutines with KMP-NativeCoroutines https://t.co/S5l89cKzmt— John O'Reilly (@joreilly) November 2, 2021
Short post about updates to BikeShare KMM sample (https://t.co/9ghVs8MAOj) to use the excellent KMP-NativeCoroutines library. Thanks @RickClephas for reviewing.