Crypto Price Widget for Home Screen (iOS and Android)
A home screen widget is a separate process that lives independently from the main app. It's not a component inside the app and not a background service with network access at any time. On iOS it's WidgetKit + SwiftUI, on Android it's Jetpack Glance or classic AppWidgetProvider. Both work on the snapshot principle: the system requests current UI at specific moments, and what displays is your responsibility.
iOS: WidgetKit and update limitations
WidgetKit doesn't allow widgets to make network requests in real time. A widget gets data via TimelineProvider, which returns an array of TimelineEntry with pre-prepared data and timestamps. The system decides when to redraw the widget.
For a crypto widget, typical strategy is updating every 15–30 minutes via TimelineReloadPolicy.atEnd or .after(date:):
struct CryptoPriceEntry: TimelineEntry {
let date: Date
let symbol: String
let price: Decimal
let change24h: Double
}
struct CryptoPriceProvider: TimelineProvider {
func getTimeline(in context: Context,
completion: @escaping (Timeline<CryptoPriceEntry>) -> Void) {
Task {
let price = try? await CryptoAPIClient.shared.fetchPrice(symbol: "BTC")
let entry = CryptoPriceEntry(date: .now,
symbol: "BTC",
price: price?.usd ?? 0,
change24h: price?.change24h ?? 0)
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 15, to: .now)!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
}
Important nuance: Apple regulates update budget. Widgets with high update frequency on low-battery devices get reduced budget — updates start arriving less frequently than requested. For trading apps requiring "data no older than 1 minute," WidgetKit is poorly suited — need to honestly explain this to the client before starting.
Passing data between main app and widget — via App Groups + UserDefaults(suiteName:) or FileManager with shared container. @AppStorage inside widget only works with App Group suite — without it, widget won't see data written by main app.
Sizes and UI adaptation
WidgetKit supports 4 sizes: .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge (iPad only). For crypto widget usually make small (symbol + price + change) and medium (several coins in a row). SwiftUI in widgets doesn't support animations, ScrollView, clicks on arbitrary areas — only Link for deep link.
Android: Jetpack Glance
Jetpack Glance — Compose-like API for widgets, appeared in 2022. Noticeably more convenient than classic RemoteViews, but has limitations: not all Compose modifiers are supported, and some API works differently than in regular Compose.
Updating data via GlanceAppWidgetManager.updateIf + WorkManager with periodic task:
class CryptoPriceWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
val prefs = currentState<Preferences>()
val price = prefs[priceKey] ?: "—"
val change = prefs[changeKey] ?: "0.0"
provideContent {
Column(
modifier = GlanceModifier.fillMaxSize().background(Color.DarkGray).padding(12.dp)
) {
Text("BTC", style = TextStyle(color = ColorProvider(Color.White), fontSize = 12.sp))
Text(price, style = TextStyle(color = ColorProvider(Color.White), fontSize = 20.sp))
Text("$change%", style = TextStyle(
color = ColorProvider(if (change.startsWith("-")) Color.Red else Color.Green)
))
}
}
}
}
Minimum update interval via AppWidgetManager — 30 minutes (Android limitation). For more frequent updates need WorkManager with PeriodicWorkRequest, but on Android 12+ background tasks are regulated by Battery Optimizer — in Doze mode intervals stretch.
What's included in the work
- iOS: WidgetKit extension,
TimelineProvider, SwiftUI layout, App Groups for shared data - Android: Jetpack Glance widget, WorkManager for updates
- Integration with price API (CoinGecko, Binance, CoinMarketCap or own backend)
- Support for multiple widget sizes
- Deep link from widget to appropriate app screen
- Testing behavior with no network and stale data
Timeline
3–5 days per platform. If both needed — 5–8 days total including shared data logic. Cost calculated individually.







