Most mobile apps store data locally on the device. This could just be some local settings/preferences but frequently also includes caching of data returned from queries to back end services. For at least the latter case that data is typically stored in an SQLite database (and, importantly, SQLite is used on both iOS and Android). There are low level libraries available to access SQLite database but this is normally achieved using libraries that provide a higher level abstraction….these typically being Core Data on iOS and, at least more recently, Room Persistence Library on Android.
SQLDelight
I mentioned the GalwayBus project in a previous article. This started life as Android only (and still predominantly is) and it had used Room library for a number of basic persistence use cases. As some of the API request logic got migrated from Android module (using Retrofit) to shared code module (using Ktor) then the need also arose for associated Repository to be able to persist/cache data in local database….and the currently accepted way of doing that, in a multiplatform project, is using SQLDelight library. SQLDelight is a Kotlin Multiplatform library that “Generates typesafe Kotlin APIs from SQL” (taking a somewhat different approach to that used by Room and CoreData). There are currently SQLDelight drivers for Android, JVM and iOS.
I’m going to outline some key components of the SQLDelight based implementation using a somewhat simplified use case from the GalwayBus project (getting/storing Bus Stop information). The main purpose of this post is really to give a flavor of how this can be done without getting too lost in the weeds. I do have to say at this point that I’ve been really impressed with how relatively straighforward it has beeen to do this and have common persistence code that runs on both iOS and Android.
The starting point is use of com.squareup.sqldelight
gradle plugin. This uses following information for example from build.gradle
and SQL such as following (in GalwayBus.sq
) to generate a number of Kotlin source files which can then be used to create and query the associated SQLite
database.
This is relevant excerpt from GalwayBusRepository.kt
(insertItem
and selectAll
apis used here were automatically generated from GalwayBus.sq
Note the use of expect fun createDb()
, the actual
versions of these are: for Android
and for iOS
Swift code such as following can be used then to call in to Kotlin GalwayBusRepository
to retrieve data (being read from database in this case).
And finally the mandatory iOS screen shot showing the bus stop data retrieved by that code.
This post has, as mentioned, been intentionally short and has just described the high level components of the solution. Full details (including for example gradle dependencies used) can be found in GalwayBus repo.
To take this further would probably require for example looking in to adding use (or not) of Column Adaptors, supporting schema migrations and how to manage observing of data updates (some interesting work being done on extension that supports Kotlin Coroutines Flow
Would also recommend watching Jake Wharton and Alec Strong’s The Resurgence of SQL talk from droidcon NYC 2017 and also Multiplatform Persistence from Alec Strong at droidcon NYC 2018
UPDATE 28th August 2019
- Wrote a short follow on post exploring newly released Flow support
- If you want to look in to SQLDelight in more detail than would definitely recommend SQLDelight 1.x Quick Start Guide for Android by Sam Edwards. He also gave an excellent talk at droidcon NYC 2019 comparing SQLDelight and Room (really recommend watching it when video become avaiiable).
Featured in Kotlin Weekly Issue #151
Related tweet
Introduction to Multiplatform Persistence with SQLDelight https://t.co/SxKHPuO1Aa
— John O'Reilly (@joreilly) June 22, 2019
Persistence is key part of #KotlinMultiplatform solution and have been really impressed at how well SQLDelight works for that. Thanks to @_modge_ and @stryni for reviewing. #iosdev #AndroidDev