Shared KMP Persistence
One storage API in commonMain — the same document code runs unchanged on Android
and iOS, reading and writing through the same MMKV-backed store on both platforms.
// commonMain
@Serializable
data class OfflineQueueItem(
val id: String,
val endpoint: String,
val payloadJson: String,
val attempts: Int = 0,
)
@Serializable
data class QueueState(
val items: List<OfflineQueueItem> = emptyList(),
)
class PendingRequestQueue {
private val doc = Documents.document<QueueState>("pending-requests")
fun enqueue(item: OfflineQueueItem) {
doc.update { current -> current.copy(items = current.items + item) }
}
fun observe(): Flow<List<OfflineQueueItem>> =
doc.flow().map { it?.items ?: emptyList() }
}
Note the queue is wrapped in a QueueState class rather than opened as
Documents.document<List<OfflineQueueItem>>("pending-requests") directly —
a top-level List is not a supported document root type today (field decomposition
keys off a class's declared properties, which a bare list doesn't have); a list works correctly
only as a field inside a @Serializable class, as shown here. See
Opening Documents for the full constraint.
PendingRequestQueue is written once, in commonMain, and used
identically from an Android ViewModel and an iOS view model — there is no
platform-specific persistence code to write or keep in sync, because the entire public API and
its logic live in commonMain. Only the underlying Storage implementation
differs per platform, and that's an internal detail the library owns. See
Storage SPI and
Platform Support for how each target is bound.