kmp-app-updater

A Kotlin Multiplatform library for in-app updates. Supports Android and Desktop (JVM).
Features
- Pluggable update sources — GitHub Releases out of the box, bring your own for GitLab / custom servers
- Streaming download with real-time progress via
StateFlow<UpdateState>
- Platform-specific installation (APK intent on Android, OS launcher on Desktop)
- Pre-built Compose Multiplatform UI components (optional)
- Configurable asset matching (
.apk, .msi, .dmg, etc.)
- Pre-release support
Modules
Quick Start
Android
Platform defaults (downloader, installer, asset matcher) are wired automatically:
val updater = AppUpdater.github(
context = applicationContext,
owner = "your-org",
repo = "your-app",
)
updater.checkForUpdate()
updater.downloadUpdate()
updater.installUpdate()
Desktop
val updater = AppUpdater.github(
owner = "your-org",
repo = "your-app",
currentVersion = "1.0.0",
)
Custom Update Source
Implement UpdateSource to connect any backend:
val updater = AppUpdater(
currentVersion = "1.0.0",
source = object : UpdateSource {
override suspend fun fetchReleases() = listOf()
},
downloader = myDownloader,
installer = myInstaller,
assetMatcher = { it.endsWith(".msi") },
)
With Compose UI
UpdateCard(updater = updater)
State Machine
Idle → Checking → UpdateAvailable → Downloading(progress) → ReadyToInstall
→ UpToDate
→ Error
Observe updater.state: StateFlow<UpdateState> for reactive UI updates.
val state by updater.state.collectAsState()
when (state) {
is UpdateState.Downloading -> DownloadProgressIndicator(state.progress, ...)
}
updater.state.collect { state -> }
Background Updates
Android (WorkManager)
Use WorkManager to check for updates periodically in the background:
class (
context: Context,
params: WorkerParameters,
) : CoroutineWorker(context, params) {
: Result {
updater = AppUpdater.github(
context = applicationContext,
owner = ,
repo = ,
)
release = updater.checkForUpdate()
(release != ) {
}
Result.success()
}
}
request = PeriodicWorkRequestBuilder<UpdateCheckWorker>(, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
,
ExistingPeriodicWorkPolicy.KEEP,
request,
)
Desktop (Coroutine Timer)
On Desktop JVM, use a coroutine-based timer to poll for updates:
fun startBackgroundUpdateCheck(updater: AppUpdater, scope: CoroutineScope) {
scope.launch {
while (isActive) {
updater.checkForUpdate()
delay(24.hours)
}
}
}
Android Setup
Add to your AndroidManifest.xml:
< = />
And res/xml/file_paths.xml:
<paths>
<cache-path name="app_updates" path="app_updates/" />
</paths>
License
Apache 2.0