Announced at WWDC last week, SwiftUI is a new declarative UI framework that is described as an “innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift.”. This approach to UI development has been popularised recently with emergence of Flutter, something that was also likely the inspiration for Jetpack Compose which was announced at Google I/O a few weeks back (SwiftUI appears to be at a significantly more advanced state of maturity than Jetpack Compose and is available to try out in Xcode 11 beta…but also important to note that it does require iOS 13).
Kotlin, unveiled by JetBrains in 2011, was initially a language targeted for the JVM. At I/O 2017, Google announced support for Kotlin for Android development and since then it’s popularity has exploded…galvanised further with the “Kotlin first” announcement at Google I/O 2019.
In recent times there’s also been an increasing interest in the Kotlin Multiplatform project and the opportunities it provides for having shared common Kotlin code running on multiple platforms…and, in particular, Kotlin/Native which allows the compilation of Kotlin for non-JVM platforms such as iOS. The feeling seems to be that this enables a more “palatable” level of code reuse (for example shared repository and data model) than say that espoused by “Cross Platform” frameworks where approach is to try and develop apps for multiple platforms from single code base (including UI). It’s worth noting that Kotlin has also become increasingly popular for developing back end services and I believe there’s also good opportunities in that context for sharing Kotlin code between client and server.
Galway Bus App
The GalwayBus project was created about 18 months ago, initially to allow exploring use of Kotlin and also the emerging Architecture Components for the development of Android applications. This became a platform then for trying out other technologies/libraries (e.g. migrating from Dagger to Koin and RxJava to Kotlin Coroutines)….and, in context of this discussion, having common Kotlin code running on Android and iOS. Kotlin Multiplatform is an area that’s still very much in development and I’d had somewhat limited success until about a week ago (just before WWDC as chance would have it!) when the stars aligned and the versions of various tools/libraries being used started working happily together!
#KotlinMultiplatform making some progress getting shared Kotlin code running on iOS and Android (in https://t.co/1docgdYeXR).Here it's using same Repo class written in Kotlin (though Android code is using suspend functions and iOS using methods that still call GlobalScope.launch) pic.twitter.com/nENNuVXmBX— John O'Reilly (@joreilly) June 2, 2019
The shared Kotlin/Native code for this made use of:
- Kotlin Coroutines
- Ktor for REST API requests
- Kotlin serialization library
- CocoaPods integration for use in XCode project
And, then, SwiftUI emerges!
So, finally, we get to point of the post! A day after my tweet above I watched the announcement of SwiftUI at WWDC and thought that the combination of
this and shared Kotlin/Native code (for, at least in this case, shared repository and data model code) looked very interesting! I downloaded
XCode 11 beta and a couple of iterations later this is what I had…certainly a much simpler/cleaner way of creating a list UI like this (compared
to using likes of storyboards,
listRoutes data was obtained using call, in Swift, to Kotlin
GalwayBusRepository code. Note how the Swift closure provided maps cleanly to Kotlin lambda.
Following is excerpt from Kotlin
GalwayBuyRepository class. The
suspend version of
used by Android code….while other one is called from iOS Swift code (use of Coroutines in Kotlin/Native code
is still something I’m getting my head around so probably cleaner way of doing this).
and following is the Kotlin
BusRoute data class used (instances of which we’re able to effectively access directly in Swift code)
It’s also interesting to note expect/actual use of
ApplicationDispatcher (used in call to
launch() above). This is defined in commonMain as
and in iosMain as
Though, as alluded to earlier, use of
GlobalScope above is far from ideal and means we don’t gain the main benefits of
structured concurrency that Kotlin Coroutines provide.
And, lastly, this is what it looks like in iOS Simulator (I clearly won’t be winning any design awards here :) but this should at least illustrate how easy it is, with SwiftUI, to add UI on top of shared Kotlin code )
Code for this is available in the GalwayBus github repo.
Featured in Kotlin Weekly Issue #150