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
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 fetchNetworkListNative
and
pollNetworkUpdatesNative
wrappers respectively for the fetchNetworkList
suspend function and pollNetworkUpdates
function
that returns a Flow
.
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
a 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
onAppear
and onDisapper
.
And finally this is screenshot from the iOS app.
Featured in Kotlin Weekly Issue #275
Related tweet
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.