Widget Abstraction & Rendering Pipeline for Kotlin Multiplatform.
Write home screen widgets once in Kotlin — render natively on Android (Glance) and iOS (WidgetKit + SwiftUI).
showcase.mp4
⚠️ Alpha Stage: WARP is currently in Alpha. APIs and implementation details may evolve based on community feedback. If you discover any bugs or have feature requests, please open an issue on GitHub Issues.
WARP is a declarative widget engine for Kotlin Multiplatform developers.
It allows you to describe home screen widget UI using familiar Compose syntax (WarpColumn, WarpRow, WarpText, WarpButton), serialize the resulting Abstract Syntax Tree (AST) to JSON, and render it using 100% native platform frameworks on each OS:
- Android: Compiles to Jetpack Glance RemoteViews.
- iOS: Compiles to SwiftUI WidgetKit extensions with interactive AppIntents.
Declarative Compose Kotlin UI ──> WarpNode AST ──> JSON ──> Native Platform Renderers
│
Shared State & Action Handlers
- ⚡ 100% Shared UI Code: Write layout logic, state models, and click actions once in
commonMain. - 🎨 True Native Views: No canvas painting or heavy Skia runtime. Renders native platform views on both Android and iOS.
- 🪶 Zero App Size Inflation: Only depends on
compose.runtime— does not pull incompose.uigraphics pipelines. - 🔄 Automatic State Store: Persistent widget state saved across system restarts using
SharedPreferences(Android) andUserDefaultsApp Groups (iOS). - 📐 Adaptive Size Bucketing: Automatically scales UI across
Small,Medium, andLargewidget sizes. - 🧙 Interactive Swift Wizard: Generate iOS WidgetKit SwiftUI and AppIntent boilerplate instantly via warp.atherio.dev/wizard.html.
Add WARP and serialization dependencies to your catalog:
[versions]
warp = "0.1.4"
kotlinx-serialization-json = "1.11.0"
compose-multiplatform = "1.11.1"
[libraries]
warp-widget = { group = "io.github.devatrii", name = "warp-widget", version.ref = "warp" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" }
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }In your shared KMP module build.gradle.kts:
plugins {
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.composeCompiler)
}
kotlin {
listOf(iosArm64(), iosSimulatorArm64()).forEach { iosTarget ->
iosTarget.binaries.framework {
export(libs.warp.widget)
}
}
sourceSets {
commonMain.dependencies {
api(libs.warp.widget)
implementation(libs.kotlinx.serialization.json)
implementation(libs.compose.runtime)
}
}
}/** 1. State */
@Serializable
data class CounterState(val count: Int = 0)
/** 2. Type-Safe Actions */
@Serializable
sealed class CounterActions {
@Serializable data object Increment : CounterActions()
@Serializable data object Decrement : CounterActions()
}
/** 3. Widget Definition */
object CounterWarpWidget : WarpWidget<CounterState>(CounterState.serializer()) {
override val id: String = "CounterWidget"
override val iosGroupId: String = "group.com.example.app"
override val stateScope: WarpWidgetStateScope = WarpWidgetStateScope.Shared
override suspend fun defaultState(): CounterState = CounterState()
@Composable
override fun Content(env: WidgetEnvironment, state: CounterState) {
WarpTheme(environment = env) {
WarpRow(
modifier = WarpModifier.fillMaxWidth().padding(16.dp),
verticalAlignment = WarpVerticalAlignment.Center
) {
WarpButton("−", CounterActions.Decrement.asClickAction())
WarpText("${state.count}", modifier = WarpModifier.weight())
WarpButton("+", CounterActions.Increment.asClickAction())
}
}
}
override fun clickHandlers(session: WarpWidgetSession): List<WarpActionHandler<*>> =
listOf(CounterActionHandler(session))
}Below is the real-world iOS build size report for the Todo Widget Example App:
| Artifact | Component / Path | Release Size | Note |
|---|---|---|---|
Xcode App Store Archive (.ipa) |
TodoWidget.ipa (App Thinning Export) |
1.8 MB | Official App Store Download Size |
| Installed App Size (Thinned) | On-Device Installed Footprint | 5.8 MB | Official App Store Install Size |
| Shared KMP Framework | SharedLogic.framework |
18.0 MB | ~73% Release Binary Stripping |
| Widget Extension Bundle | TodoWidgetExtension.appex |
8.50 MB | Uncompressed bundle on-disk |
| Module | Role |
|---|---|
| warp-runtime | Compose compiler DSL, WarpNode AST tree, WarpModifier chain, serializable actions |
| warp-ui | Native platform renderers — Jetpack Glance (Android) & SwiftUI generator (iOS) |
| warp-widget | Shared WarpWidget API, session manager, persistent state store, WarpTheme, WarpAdaptive |
| warpWidgetKit | SPM SwiftUI / WidgetKit package (import warpWidgetKit) for Xcode extensions |
| shared | Shared KMP module with Counter widget demo |
| examples/todo-widget | Complete full-featured Todo Widget example application |
- 📖 Official Documentation: https://warp.atherio.dev
- 🧙 iOS Widget Wizard: https://warp.atherio.dev/wizard.html
- 💡 How WARP Works: How WARP Works Under the Hood
WARP is open-source software released under the MIT License. You are free to use, modify, and distribute it in personal or commercial applications.
