Hello Apple DTS Team,
We are optimizing a real-time iOS 26 WidgetKit architecture that utilizes both direct WidgetKit APNs pushes and Notification Service Extension (NSE) background asset downloading. We would appreciate technical clarification regarding budget allocation, execution latency, and view hierarchy invalidation on iOS 26.
Architecture Overview
Our system handles real-time visual updates across multiple distinct Widget kinds (KindA, KindB) using a dual-path pipeline:
-
Direct WidgetKit APNs Push (iOS 26):
- Registers tokens via
WidgetPushHandler(pushTokenDidChange(_:widgets:)). - Remote server sends APNs requests targeting
<bundleID>.push-type.widgetswithapns-push-type: widgetsand payload{"aps": {"content-changed": true}}.
- Registers tokens via
-
NSE Asset Pre-Fetch (Notification Service Extension):
- Server sends a remote notification containing
mutable-content: 1and asset metadata. - The NSE intercepts the payload, streams the binary image asset into a shared App Group container (
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:)), writes JSON state to sharedUserDefaults, and executes targeted timeline reloads viaWidgetCenter.shared.reloadTimelines(ofKind: "KindA").
- Server sends a remote notification containing
-
Timeline Provider:
TimelineProvider.getTimeline()reads data synchronously from the shared App GroupUserDefaults, resolves the local file path viaUIImage(contentsOfFile:), and returns a singleSimpleEntrywithTimelineReloadPolicy.after(25 minutes)alongsideTimelineEntryRelevance(score: 100.0).
Technical Questions & Observed Behaviors
-
Per-Kind Budget Isolation vs. Bundle-Wide Budget:
- Does
dasd/chronodmaintain an independent 70-reload daily budget for each individual Widget kind (or widget instance), or is the daily background reload budget shared globally across all widget kinds within the extension bundle? - Does calling
WidgetCenter.shared.reloadTimelines(ofKind: "KindA")from an NSE deduct budget tokens only fromKindA's budget bucket, or does it deduct from a global shared bundle pool?
- Does
-
NSE Reload Budget Deductions vs. Direct WidgetKit Pushes:
- Does a direct WidgetKit APNs push (
apns-push-type: widgets) draw from a completely separate APNs push budget pool than aWidgetCenter.shared.reloadTimelines(ofKind:)call issued inside an NSE? - When an NSE issues
reloadTimelines(ofKind:)in response to a user-visible notification (alert+mutable-content: 1), does iOS grant notification grace tokens that bypass standard_DASWidgetBudgetdeductions?
- Does a direct WidgetKit APNs push (
-
WidgetKit Push Notification Delivery & Rendering Inconsistencies on iOS 26: When sending direct WidgetKit APNs pushes (
apns-push-type: widgets), we observe 3 distinct, inconsistent behaviors in production on iOS 26:a) Successful Instant Update: APNs push arrives → WidgetKit wakes up immediately →
getTimeline()executes (<0.1s) → Home Screen widget displays the new image instantly.b) Complete Execution Drop: APNs push is sent by our server (HTTP 200 response from APNs
api.push.apple.com) → WidgetKit never wakes up, andgetTimeline()is completely ignored/not invoked by iOS.c) Execution Success but Screen Bitmap Stale: APNs push arrives →
getTimeline()wakes up, executes, and loads the image successfully from disk (UIImage(contentsOfFile:)returns a valid image) →completion(Timeline(entries: [entry]))returns → BUT the displayed image on the Home Screen does NOT change or repaint until the user opens the main app.Questions for DTS Engineers:
- Why does iOS 26 occasionally drop
getTimelineinvocation for directapns-push-type: widgetspushes even when APNs returns HTTP 200? - Is
Image(uiImage:)rendering inside WidgetKit subject to view hierarchy caching if theSimpleEntrystruct date is updated but SwiftUI considers the view tree structurally identical? Does binding an explicit.id(assetPath)modifier to theImageview force SpringBoard's compositor layer to invalidate and repaint immediately upongetTimelinecompletion?
- Why does iOS 26 occasionally drop
Thank you for your guidance!