跪拜 Guibai
← All articles
Kotlin · Android · Open Source

Syncox Brings Fire-and-Forget Offline Sync to Kotlin Multiplatform

By 机智的张尼玛 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Mobile apps that block the UI on every network call feel broken the moment connectivity degrades. An outbox library that requires only an annotation and a data class removes the boilerplate that makes offline-first architecture too expensive for most teams to adopt.

Summary

Syncox implements the outbox pattern directly on the client, persisting every user action to a local SQLite database before the network call even begins. The UI updates instantly, and a background daemon handles retries with exponential backoff, erasing records only after a confirmed success.

Integration relies on KSP compile-time code generation. Developers define an action payload and annotate the existing suspend function with `@OfflineSync`; the library builds a reflection-free routing table so the engine can invoke the right endpoint automatically. ViewModel code collapses to a single `Syncox.enqueue()` call, with an optional `Flow` for observing pending sync counts.

The project targets Android and KMP (iOS, Desktop) and is designed to drop into existing Ktor or Retrofit stacks without refactoring network layers.

Takeaways
User actions are serialized to JSON and written to a local SQLite database immediately, returning UI success in under 1ms.
A KSP annotation processor generates a type-safe routing table so the sync engine can call the correct network function without reflection.
Each annotated function returns a `NetworkResult` that tells the engine whether to erase the record, retry with backoff, or treat the failure as fatal.
The library exposes a `Flow<Int>` of pending action counts, letting Compose or other UI frameworks show background sync status with no extra state management.
Syncox works with existing Ktor or Retrofit setups and supports Android, iOS, and Desktop through Kotlin Multiplatform.
Conclusions

Client-side outbox implementations are common inside large apps like WeChat but rarely packaged as a standalone library, leaving smaller teams to reinvent retry queues and local persistence for every project.

Making the sync engine annotation-driven rather than requiring a base class or interface hierarchy keeps the network layer untouched, which lowers the risk of adopting the pattern in an existing codebase.

The library's design treats the network call as a pure function of a JSON string, which means the same engine can drive completely different API styles (REST, GraphQL, gRPC) as long as they can be wrapped in a suspend function.

Concepts & terms
Outbox Pattern
A messaging pattern where data is written to a local outbox table in the same transaction as the business operation; a separate process then reads the outbox and delivers the messages reliably. On the client, this means persisting the user's intent locally and syncing it to the server asynchronously.
KSP (Kotlin Symbol Processing)
A compile-time code generation API for Kotlin that runs directly on Kotlin's compiler AST, avoiding the overhead of annotation processors like KAPT. Syncox uses it to generate a routing table that maps action types to their network functions.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗