Home-screen widgets
watchlist and portfolio.
Two widgets on Android and iOS: the watchlist (up to 4 coins with price and 24-hour change) and the selected portfolio's value. They refresh themselves every 30 minutes from your API.
01The two widgets
| Widget | Shows | Tap |
|---|---|---|
| Watchlist | Price and 24-hour change of up to 4 coins from the user's watchlist, in the user's currency | Opens the app; tapping a coin row opens that coin |
| Portfolio | The selected portfolio's value and 24-hour change | Opens the app |
They follow the system light or dark mode and are translated into the 9 app languages. The web demo has no widgets.
02How they get data
- The app writes the watchlist, the selected portfolio and your
API_BASE_URLto storage the widgets can read (app/lib/services/widget_sync.dart, packagehome_widget). On Android that is theHomeWidgetPreferencesSharedPreferences; on iOS the App Group shared with the widget extension. - Between app launches the widgets fetch fresh prices themselves from
<API_BASE_URL>/v1/markets?ids=…every 30 minutes: on Android with WorkManager (WidgetRefreshWorker.kt), on iOS with a WidgetKit timeline (WidgetStore.swift). The operating system decides the exact moment, so a refresh can come later. - No key and no account are involved: the markets endpoint is public and cached.
03Switch widgets off, or make them Pro-only
Two console switches control the widgets without a new build. The app applies them each time it loads the configuration (app/lib/bootstrap.dart, docs/CONTRACT.md §7).
| Console setting | Default | What the user's widgets show |
|---|---|---|
| Features → Home-screen widgets off | On | "Open the app to enable widgets" |
| Pro and purchases → Home-screen widgets for Pro only on | Off | "Widgets are a Pro feature" for users without Pro. Applies only while Offer Pro is on; otherwise nobody could unlock them, so the widgets keep showing data. |
- While a notice is shown the widgets hold no prices and do not refresh themselves. The notice is translated into the 9 languages (
ct_widget_disabled_offandct_widget_disabled_proon Android,disabled.offanddisabled.proon iOS). - The app keeps the watchlist and portfolio and shows them in the widgets again as soon as the switch is turned back, or the user gets Pro.
- The app waits until it knows whether the user has Pro, so a Pro user's widgets do not briefly show the notice at start.
- A widget only changes after the app has started once with the new configuration.
04Android files
| File | What |
|---|---|
app/android/app/src/main/kotlin/com/yourcompany/cryptotracker/ | WatchlistWidgetProvider.kt, PortfolioWidgetProvider.kt, WidgetViews.kt, WidgetStore.kt, WidgetRefreshWorker.kt |
app/android/app/src/main/res/layout/ct_widget_*.xml | Layouts |
app/android/app/src/main/res/xml/ct_widget_*_info.xml | Sizes and the preview |
app/android/app/src/main/res/values*/ct_widget_*.xml | Texts per language, colours (light and values-night), dimensions |
The receivers are declared in AndroidManifest.xml. The Dart side refers to them by the Kotlin package (com.yourcompany.cryptotracker), not by the application id, so changing applicationId alone does not break widget updates.
05iOS widget extension
| File | What |
|---|---|
app/ios/CryptoTrackerWidget/CryptoTrackerWidget.swift | The two widgets, their look (accent #10B981, light and dark) and timeline |
app/ios/CryptoTrackerWidget/WidgetStore.swift | Reads the App Group and refreshes prices |
app/ios/CryptoTrackerWidget/*.lproj/ | Texts in 9 languages |
app/ios/CryptoTrackerWidget/CryptoTrackerWidget.entitlements | The App Group |
app/ios/scripts/add_widget_extension.rb | Adds or repairs the extension target in the Xcode project |
The extension target is already in Runner.xcodeproj, with bundle id <app bundle id>.CryptoTrackerWidget and iOS 15.0. Sign it with your team in Xcode. Run the script only after a rebrand or if the target got lost:
cd app/ios
ruby scripts/add_widget_extension.rb # idempotent; uses the xcodeproj gem that ships with CocoaPods
06The App Group must match in four places
The app and the widget share data through the App Group group.com.yourcompany.cryptotracker. When you change the bundle id, change the group in all of these, register it in your Apple Developer account and enable it for both App IDs:
app/ios/Runner/Runner.entitlementsapp/ios/CryptoTrackerWidget/CryptoTrackerWidget.entitlementsapp/ios/CryptoTrackerWidget/WidgetStore.swift(appGroup)app/lib/services/widget_sync.dart(appGroup)
A mismatch shows as an iOS widget in its empty state even though the app has data.
07Change the look
Widget colours are native, not taken from the console's accent: edit Theme in CryptoTrackerWidget.swift and values/ct_widget_colors.xml plus values-night/ct_widget_colors.xml on Android. See Rebranding.