Most of the focus of Kotlin Multiplatform has, understandably, been on targeting the development of apps that run on Android and iOS. However, other platforms are supported so when I saw following announcement of SQLDelight’s support for macOS I was curious to see what would be involved in developing a basic app on that platform that uses same shared Kotlin code used in PeopleInSpace (A little bit more background on initial effort working with Android and iOS in following post Minimal Kotlin Multiplatform project using Compose and SwiftUI)
SQLDelight 1.2.2 released with windows/watchOS/tvOS/macOS support!https://t.co/vK27TSSVqF
— Alec Strong (@Strongolopolis) January 23, 2020
also the whole thing is on github actions now! There's even an EAP channel for the intellij plugin that automatically gets pushed too!!! Wow!!!!!
The Android, iOS and watchOS apps in PeopleInSpace had just displayed a list of astronauts currently in space but, given
additional real estate at our disposal on macOS, I thought I should expand to include other information available from
People In Space API endpoint so decided to also show current position of ISS (International Space Station)
Updated Ktor client code
There isn’t anything macOS specific here but did add use of API that returns ISS position.
@Serializable
data class AstroResult(val message: String, val number: Int, val people: List<Assignment>)
@Serializable
data class Assignment(val craft: String, val name: String)
@Serializable
data class IssPosition(val latitude: Double, val longitude: Double)
@Serializable
data class IssResponse(val message: String, val iss_position: IssPosition, val timestamp: Long)
@UnstableDefault
class PeopleInSpaceApi {
private val baseUrl = "http://api.open-notify.org"
private val client by lazy {
HttpClient() {
install(JsonFeature) {
serializer = KotlinxSerializer(Json(JsonConfiguration(isLenient = true, ignoreUnknownKeys = true)))
}
}
}
suspend fun fetchPeople() = client.get<AstroResult>("$baseUrl/astros.json")
suspend fun fetchISSPosition() = client.get<IssResponse>("$baseUrl/iss-now.json")
}
macOS SwiftUI code
The SwiftUI code used is similar to that used for iOS and watchOS but now includes use of a Map View to show ISS position (along with associated
update to View Model). This is using Combine’s Timer.publish()
to periodically
poll for updated position. Another approach might be to do the polling in shared Kotlin Code (perhaps an exercise for someone if they
want to create PR for this :) )
struct ContentView: View {
@ObservedObject var peopleInSpaceViewModel = PeopleInSpaceViewModel(repository: PeopleInSpaceRepository())
let timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
List(peopleInSpaceViewModel.people, id: \.name) { person in
PersonView(person: person)
}
.listStyle(SidebarListStyle())
.onReceive(timer) { _ in
self.peopleInSpaceViewModel.fetchISSPosition()
}
.onAppear(perform: {
self.peopleInSpaceViewModel.fetchPeople()
self.peopleInSpaceViewModel.fetchISSPosition()
})
MapView(coordinate: CLLocationCoordinate2DMake(peopleInSpaceViewModel.issPosition.latitude, peopleInSpaceViewModel.issPosition.longitude))
}
}
}
struct PersonView : View {
var person: Assignment
var body: some View {
Text(person.name + " (" + person.craft + ")")
}
}
Gradle updates
These are the main updates to build.gradle
for shared code module.
fromPreset(presets.macosX64, 'macOS') {
binaries {
framework('common')
}
}
macOSMain.dependencies {
// Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-macosx64:${Versions.kotlinCoroutines}"
// Ktor
implementation "io.ktor:ktor-client-curl:${Versions.ktor}"
implementation "io.ktor:ktor-client-core-macosx64:${Versions.ktor}"
implementation "io.ktor:ktor-client-json-macosx64:${Versions.ktor}"
implementation "io.ktor:ktor-client-logging-macosx64:${Versions.ktor}"
implementation "io.ktor:ktor-client-serialization-macosx64:${Versions.ktor}"
// Serialize
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-macosx64:${Versions.kotlinxSerialization}"
// SQL Delight
implementation "com.squareup.sqldelight:native-driver-macosx64:${Versions.sqlDelight}"
implementation "com.squareup.sqldelight:runtime-macosx64:${Versions.sqlDelight}"
}
Note
This is currently using 1.3.5-native-mt
version of Kotlin Coroutines. Ktor does not currently fully work with this version so, for
now this is using runBlocking
workaround when invoking API requests - more info in this Ktor issue
Featured in Kotlin Weekly Issue #194
Related tweet
Just wrote short blog article on starting to use #KotlinMultiplatform on macOS https://t.co/XDrUa7QxOf https://t.co/KGzdFTcE45
— John O'Reilly (@joreilly) April 18, 2020