Widgets & Live Activities

RSS for tag

Discuss how to manage and implement Widgets & Live Activities.

WidgetKit Documentation

Posts under Widgets & Live Activities subtopic

Post

Replies

Boosts

Views

Activity

Maximise background update on WatchOS
I'm looking to maximise my Watch app's widget to be as up to date as possible. If we imagined the app was a simple step counter, and we wanted to display the users count as up to date as possible. We can conclude: We don't care about widget timelines beyond the current entry as we can't predict the future! We need to refresh the count as often as possible The refresh should be very quick with a straightforward HealthKit query, no networking or heavy work needed. We will assume the user has the complication/widget on their active Watch face. With the standard WidgetKit APIs we can expire the timeline after 15 minutes and in my experimentation a Watch app can usually update its widget timeline at that frequency if it's on the Watch face. I'm experimenting with two methods to try and improve refreshes further A user's step count might not have recently changed when the timeline update is called. I was therefore looking into the HealthKit enableBackgroundDelivery API (which requires the HealthKit Background Delivery entitlement to be enabled) to get updates limited to once an hour from a HKObserverQuery, I can then call the WidgetCenter.shared.reloadAllTimelines() from there. WatchOS also support the BGAppRefreshTaskRequest(identifier:"") and .backgroundTask(.appRefresh) APIs. I can request updates once every 15 minutes here too and then call the WidgetCenter.shared.reloadAllTimelines(). With option 1, this update opportunity is great as it will specifically update when there's new steps so even once an hour this would be helpful (A real shame to be limited to once an hour even if this used up WidgetKit standard reload budgets: FB13879817, FB11677132, FB10016177). But I can't determine if this update takes away one of the standard timeline expiration updates that already run 4 times an hour? Could I observe additional Health types to get additional updates? Do I need the Background Modes Capability as well as the HealthKit Background Delivery for this in Xcode or just the HealthKit one? With option 2, I can't find a suitable option in the (short) list of supported background modes in Xcode. Does not selecting any mean my app will get 0 refreshes from this route and so should not be implemented in my use case?
3
1
126
Jun ’25
Live Activity in terminated state
Hi. I need some help in starting the live activity in terminated state using push notification. I have developed an app which does not sleep and always run even in the background state. It is pressure calculator. From sensor, it will receive the pressure and display the values in the app. Whenever the pressure reaches a certain point, it should display the alert in the dynamic island. As of now, it is displaying live activity in the foreground state. Working partially fine in the background state. But not working in the terminated state. but in the documentation it have been mentioned we can start the live activity using push notification from any state. Please help me to find a solution.
1
1
62
Jul ’25
On iOS, using the AppIntents framework, I need a conditional AppShortcutsProvider
We have a Subscription based feature in our App, using which a user can say something like "Ask Mickey". However we want to enable this system Shortcut only when the user has subscribed to certain premium features. i.e. If the User is not subscribed to Premium Services, we do not want to show this Shortcut. However, when adding any conditional code inside AppShortcutsProvider, I am getting the following Compile Time errors: **'AppShortcutsProvider' property 'appShortcuts' requires builder syntax AppShortcut builders support only a platform availability if statements, not general if statements'**
0
1
40
Jul ’25
Can We Display Screen Time Data in WidgetKit?
Hello, I am trying to create a Home Screen widget for iOS that displays device usage statistics — similar to the built-in Screen Time widget Apple provides. The goal is to show the average device usage for a specified period (daily, weekly, or monthly) and optionally include a comparison with the previous period. I noticed that Apple’s own Screen Time widget presents such information. However, after reviewing the public documentation, I could not find any available API that allows a developer to create a similar experience. To explore possible alternatives, I implemented a SwiftUI view inside a com.apple.deviceactivityui.report-extension using the Family Controls and Device Activity frameworks. The view works fine within the main app and the report extension context, but when I attempted to use the same view in a WidgetKit extension, I received an error at runtime. This suggests that views from com.apple.deviceactivityui.report-extension are not usable inside widgets, which I understand may be due to sandboxing or limitations of how the extension points are designed. So far, I’ve found no way to access cumulative or average usage data (screen time, app usage, etc.) from system APIs that can be shown in a widget context. My understanding is that Family Controls and Device Activity frameworks allow observing ongoing activity and building usage reports inside the app, but do not provide access to the same historical or summarized data that Apple’s own widgets display. Could you please confirm: Whether there is any supported way to access average device usage (screen time) data for use in a widget? If not, is this an intentional limitation due to privacy concerns, or is there a roadmap for exposing such APIs in the future? Are there any APIs or entitlements that could allow similar functionality via WidgetKit? Thank you for your time and support. Best regards,
2
1
141
Jul ’25
New push notifications for widgets seem too limited for actual production-level apps
I was very excited to see the addition of push notifications for widgets. However upon further inspection, the way it is implemented seems too limiting for real life apps. I have an app for time tracking with my own backend. The app syncs with my backend in the main executable (main target). My widgets are more lightweight as they only access data in the shared app container, but they don't perform sync with the server directly to avoid race conditions with the main app. I was under the impression that the general direction of the platform is to be doing most things in the main app target (also App Intents work that way for the most part), so the fact that the WidgetPushHandler just calls the widget's method to reload the timeline is very unfortunate. In an ideal scenario I also need the main app to be 'woken up' to perform the sync with the server, and once that's done I'd update the widget's timeline and where I would just read data from the shared app container. So, my questions are: What is the recommended way of updating the widgets when this push notification arrives in the case that the main app target needs to perform the sync first? Is there any way how to detect that the method func timeline(for configuration: InteractiveTrackingWidgetConfigurationAppIntent, in context: Context) was called as a result of the push notification being received? Can I somehow schedule a background task from the widget's reloadTimeline() function? How can I get the push token later, in case that I don't save it right away the first time the WidgetPushHandler's pushTokenDidChange() is called? Thank you for your work on this and hopefully for your answers. FB19356256
2
1
90
Sep ’25
Detect if a widget is displayed in CarPlay vs. iPhone/iPad
I am looking into the new CarPlay support for systemSmall widgets introduced in iOS 26 (Apple documentation). I am trying to figure out if there is a way to programmatically detect whether the widget is currently being displayed on the iPhone/iPad home/lock screen or in CarPlay. So far, I haven’t found any information in the documentation or APIs that indicate how to distinguish between these environments. Is there an API, environment value, or best practice for handling this scenario? Thanks in advance for any insights!
0
1
88
Aug ’25
Title and Subtitle in Control Widget on macOS Tahoe?
Hi 🙋 Has anybody gotten subtitles in macOS Tahoe Control Widgets to show up in their custom control widgets? Seems macOS is able to do it (see attached screenshot of the Bluetooth control widget), but my widget, which shows a title and subtitle on iOS, will only show the title on macOS. I tried all the different ControlWidgetButton init methods to no avail. I tried a VStack for my title and subtitle Texts, I tried just two Texts without a VStack, I tried the controlWidgetStatus and controlWidgetActionHint modifiers out of desperation... nothing worked. Any pointers much appreciated! Thank you, – Matthias
2
1
133
4w
how to suppress sound of a live activity when app is foregrounded?
Regular apns will give you a willPresent callback and there you can decide to suppress showing the notification or suppress its sound etc. I know the iOS app will give you callbacks for when there's a contentUpdate, yet that doesn't give the option to change the sound. Is there a way to suppress sound of a received Live Activity when app is in foreground?
0
1
47
2w
Live activity custom format timer
We need a live activity to countdown our time in formats like 2h 30m -> 2h 29m -> 2h 28m etc 58m -> 57m I see this kind in pictures in official documentation. to make a functional timer is: Text(context.state.startTime, style: .timer) But it's very limited when it comes to formatting. This timer .relative includes seconds which we don't want Text(futureDate, style: .relative) Also format we need is h instead of hour, m instead of min
0
1
22
2w
AppIntentConfiguration WatchOS & iOS inconsistent
I'm having problems with my released app with iOS & WatchOS 26 support. I've added AppIntentConfiguration support in the WatchOS app such that users can configure the complication. My complications also support multiple families and so I have slightly different configuration options available if its in the .accessoryRectangular slot or the .accessoryCircular one. This works fine on Apple Watch when editing the Watch face. Here you can then select the configuration options fine and they are correct for the different variants. However on iOS when configuring in the Apple Watch app on iPhone, the different complication size is ignored and the same configuration options are offered meaning they are wrong for one of them. I created a sample project, here is the app intent code: struct TestWidgetConfigurationIntent: AppIntent, WidgetConfigurationIntent { static var title: LocalizedStringResource = "New Widgets with Configuration" static var description = IntentDescription("Lots of stuff.") static var isDiscoverable: Bool { return false} init() {} func perform() async throws -> some IntentResult { return .result() } @Parameter(title: "Enable More Detail", default: true) var moreDetail: Bool @Parameter(title: "Enable Other Parameter", default: true) var otherParameter: Bool static var parameterSummary: some ParameterSummary { When(widgetFamily: .equalTo, .accessoryRectangular) { Summary("Test Info") { \.$moreDetail \.$otherParameter } } otherwise : { Summary("Test Info") { \.$moreDetail } } } } In WatchOS you get the correct configuration options: In iOS you do not, you get the same configuration option regardless of which family size you select: This could be a bug so I've filed feedback FB20328319. Otherwise if anyone has insights, it would be very appreciated. This is all tested on the current iOS 26.0 and WatchOS 26.0 versions. Thanks!
1
1
88
1d
Unable to activate ActiveKit
Appears during code compilation Provisioning profile "iOS Team Provisioning Profile: ..*" doesn't include the com.apple.developer.ActivityKit entitlement, Has anyone encountered or resolved a similar issue where the ActiveKit feature was not found in the developer's identifier, despite not being activated in the developer's system?
1
1
57
1w
App widget not appearing in widget list (intermittent)
There seems to be a long running issue with WidgetKit where some users don't see the widget when trying to add to their Home Screen. (even after opening the app for the first time). I have been able to reproduce myself intermittently, and typically restarting the phone or re-installing the app fixes the problem. However, some of my users have encountered this and end up requesting refunds because they think the app is broken. Has anybody else experienced this issue? Would be great to get this bug resolved as it's frustrating for users.
1
2
515
1w
[Widget] ChronoKit.InteractiveWidgetActionRunner.Errors.runnerClientError `There is no metadata for `
In our widget we include a button with an intent, making a network call to refresh some shared data in its perform(). Whether the call finishes in time or not is not important to us, what matters more is that the widget gets reloaded at the end and displays whatever data it has available with its transition animation. On iOS18.0 we see the widget being reloaded but on the latest version 18.4 this doesn't happen anymore. Going through the logs, on both devices we see this same flow: default 2025-04-10 15:05:26.853674 +0300 WidgetRenderer_Default Evaluating dispatch of UIEvent: 0x300e002a0; type: 0; subtype: 0; backing type: 11; shouldSend: 1; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.853691 +0300 WidgetRenderer_Default Sending UIEvent type: 0; subtype: 0; to windows: 1 default 2025-04-10 15:05:26.853702 +0300 WidgetRenderer_Default Sending UIEvent type: 0; subtype: 0; to window: <WidgetRenderer.WidgetWindow: 0x5689b4000>; contextId: 0x8E401B8A default 2025-04-10 15:05:26.853735 +0300 SpringBoard Evaluating dispatch of UIEvent: 0x300af9420; type: 0; subtype: 0; backing type: 11; shouldSend: 1; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.853836 +0300 SpringBoard Sending UIEvent type: 0; subtype: 0; to windows: 1 default 2025-04-10 15:05:26.853864 +0300 SpringBoard Sending UIEvent type: 0; subtype: 0; to window: <_UISystemGestureWindow: 0xb5a20d000>; contextId: 0x5A4C4C23 default 2025-04-10 15:05:26.854862 +0300 SpringBoard Evaluating dispatch of UIEvent: 0x300aeeca0; type: 0; subtype: 0; backing type: 11; shouldSend: 1; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.854866 +0300 WidgetRenderer_Default [Timeline[<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget:systemMedium::321.00/148.00/20.20:(null)]--A76785AED3F9::0xb5bc4c000)] Handle action default 2025-04-10 15:05:26.854892 +0300 SpringBoard Sending UIEvent type: 0; subtype: 0; to windows: 1 default 2025-04-10 15:05:26.854901 +0300 SpringBoard Sending UIEvent type: 0; subtype: 0; to window: <SBHomeScreenWindow: 0xb5ad60000>; contextId: 0x71D69FA2 default 2025-04-10 15:05:26.855015 +0300 WidgetRenderer_Default Handle action: <private> default 2025-04-10 15:05:26.855360 +0300 SpringBoard Allowing tap for icon view '<private>' default 2025-04-10 15:05:26.855376 +0300 SpringBoard Not allowing tap gesture to begin because we're not editing, the custom view controller's user interaction is enabled, and the effective icon alpha isn't zero. default 2025-04-10 15:05:26.856940 +0300 SpringBoard Icon touch ended: <private> default 2025-04-10 15:05:26.857474 +0300 backboardd contact 1 presence: none default 2025-04-10 15:05:26.857826 +0300 chronod Received action <private> for interaction <WidgetRenderSession--4632871937259503361-scene::C1F20222-CC99-45CC-B074-A76785AED3F9::0xb5bc4c000-[<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget:systemMedium::321.00/148.00/20.20:(null)]> default 2025-04-10 15:05:26.858381 +0300 chronod [<WidgetRenderSession--4632871937259503361-scene::C1F20222-CC99-45CC-B074-A76785AED3F9::0xb5bc4c000-[<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget:systemMedium::321.00/148.00/20.20:(null)]>] Handle interaction: <private> default 2025-04-10 15:05:26.858436 +0300 chronod Pausing reloads for: [<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget] default 2025-04-10 15:05:26.869525 +0300 chronod [0xd180b2440] activating connection: mach=true listener=false peer=false name=com.apple.linkd.registry default 2025-04-10 15:05:26.870054 +0300 WidgetRenderer_Default Evaluating dispatch of UIEvent: 0x300e002a0; type: 0; subtype: 0; backing type: 11; shouldSend: 0; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.870124 +0300 SpringBoard Evaluating dispatch of UIEvent: 0x300af9420; type: 0; subtype: 0; backing type: 11; shouldSend: 0; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.870198 +0300 SpringBoard Evaluating dispatch of UIEvent: 0x300aeeca0; type: 0; subtype: 0; backing type: 11; shouldSend: 0; ignoreInteractionEvents: 0, systemGestureStateChange: 0 default 2025-04-10 15:05:26.871831 +0300 linkd Accepting XPC connection from PID 129 for service "com.apple.linkd.registry" default 2025-04-10 15:05:26.871840 +0300 linkd [0x410cbe6c0] activating connection: mach=false listener=false peer=true name=com.apple.linkd.registry.peer[129].0x410cbe6c0 info 2025-04-10 15:05:26.876032 +0300 chronod Client requested ( "<LNFullyQualifiedActionIdentifier: 0xd17321b40, bundleIdentifier: <edited-bundle-identifier>, actionIdentifier: ReloadBalanceIntent>" ), got { } default 2025-04-10 15:05:26.877178 +0300 chronod [0xd180b2440] invalidated because the current process cancelled the connection by calling xpc_connection_cancel() default 2025-04-10 15:05:26.877377 +0300 linkd [0x410cbe6c0] invalidated because the client process (pid 129) either cancelled the connection or exited Then it followa with this on iOS18.4 : error 2025-04-10 15:21:32.964920 +0300 chronod [<WidgetRenderSession-7817322460413849944-scene::B5E4D7C4-91E1-4656-8175-C3C3C1CB894D::0xc733b8000-[<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget:systemLarge::364.00/382.00/23.00:(null)~(null)]>] Encountered error when handling interaction: ChronoKit.InteractiveWidgetActionRunner.Errors.runnerClientError(Error Domain=WFLinkActionWorkflowRunnerClientErrorDomain Code=1 "There is no metadata for ReloadBalanceIntent in `<edited-bundle-identifier>`" UserInfo={NSLocalizedDescription=There is no metadata for ReloadBalanceIntent in `<edited-bundle-identifier>`}) default 2025-04-10 15:21:32.964958 +0300 chronod [<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget] Resuming reloads. Reload state paused -> clean info 2025-04-10 15:21:32.965013 +0300 chronod [interactionFailed] All diagnostics are disabled. Whereas on iOS18.0 it follows with a simplified error: error 2025-04-10 15:05:26.879005 +0300 chronod [<WidgetRenderSession--4632871937259503361-scene::C1F20222-CC99-45CC-B074-A76785AED3F9::0xb5bc4c000-[<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget:systemMedium::321.00/148.00/20.20:(null)]>] Encountered error when handling interaction: Error Domain=ChronoKit.InteractiveWidgetActionRunner.Errors Code=1 default 2025-04-10 15:05:26.879065 +0300 chronod Resuming reloads for: [<edited-bundle-identifier>::<edited-bundle-identifier>.<Widget>:widget] but afterwards we see many lines describing the reload process. So it turns out that the intent fails(?) to execute on both OSes but iOS18.0 triggers a reload even so, which fits our purposes. What could the issue be? The intent is pretty standard, it contains only the title, localizedDescription and is defined only inside the widget.
1
2
83
Apr ’25
reloadAllTimelines() is broken on watchOS 11.5
I am experiencing an issue with my watchOS app. My application updates a shared file, accessible by both the main app and the WidgetKit extension, during a WatchConnectivity background task. Following this update, I call reloadAllTimelines(). This functionality worked as expected on watchOS 10, even without Developer Mode enabled. However, after updating my device to watchOS 11.5, this API appears to be broken. My reasons for believing this API is broken are threefold: The functionality worked reliably on watchOS 10. On watchOS 11.5, enabling "WidgetKit Developer Mode" (found under Settings > Developer) resolves the issue, and my complications update correctly. When I enter watch face edit mode, the snapshot/preview displayed (which utilizes the same underlying logic as the timeline API) shows the correct data. This indicates that the data has been successfully received from the phone, and the widget is indeed reading the updated shared file. Despite this, the actual widget view during its resting phase never updates. It's worth noting that TimelineReloadPolicy functions as expected, but I cannot rely on this for my use case. My widget requires immediate updates upon receiving new data. Apple, please investigate this behavior.
1
2
130
Jun ’25
Migrate Widgets from StaticConfiguration to IntentConfiguration
New features in WatchOS 26 with configurable widgets make it more important than ever that apps adopt IntentConfiguration options where applicable. I develop an app with an Apple Watch complication/widget on many many user's Watch faces around the world. I've completed updating my code to support WidgetKit and remove ClockKit. However, I face huge issues adding support for users to configure their widget/complications. If I update a widget to go from StaticConfiguration to IntentConfiguration, even when keeping the "kind" string the same, the widget disappears from the Watch face. This is an unacceptable user experience meaning I can't proceed with the migration. The problem is users will expect me to offer configuration in the Watch face soon for their widget/complication. Currently this process is done in a sub-optimal way in the app itself. A similar issue exists on iOS where the widget will just "freeze" indefinitely is migrated. This issue still occurs on the iOS 26 and WatchOS 26 betas. So how to move this forward. This has been discussed previously here: https://developer.apple.com/forums/thread/661247 I've mentioned it at WidgetKit labs I've filed feedback last year: FB13880020 I've filed feedback this year: FB18180368 It seems really important this gets fixed for developers to adopt these new features, is there any other migration route I'm missing or a workaround that would mitigate this seemingly big problem.
4
1
145
2w
Live Activity PushToken Not Callback
I have start new live activity with push notifications,but sometimes this code"activity.pushTokenUpdates" can not callback to me,so I can't update the activity with push notifications. And I already click “Allow” button in my live activity widget.How can I solve this problem. Here are my code: fileprivate func observeLiveActivityForRemoteCreate() { // obverser pushToStartToken Task { if #available(iOS 17.2, *) { var beforeToken = "" for await pushToken in Activity<HLPlatformActivityAttributes>.pushToStartTokenUpdates { let pushTokenStr = pushToken.map{String(format: "%02.2hhx", arguments: [$0])}.joined() // avoid send duplication if beforeToken == pushTokenStr { return } beforeToken = pushTokenStr // send pushToStartToken to service await HLPlatformLiveActivityBridge.registerLiveActivity(withAttributesName: self.activityAttributesName, pushToStartToken: pushToken, seq: seqCreate(), pushType: .jPush) } }else { // Fallback on eralier versions } // obverser live activity update Task { for await activity in Activity<HLPlatformActivityAttributes>.activityUpdates { if let businessLiveActivityId = activity.attributes.businessLiveActivityId, let liveActivityId = activity.attributes.liveActivityId { Task { var beforeToken = "" for await pushToken in activity.pushTokenUpdates { // here the problem:sometimes pushToken not update to me let pushTokenStr = pushToken.map{String(format: "%02.2hhx", arguments: [$0])}.joined() // avoid send duplication if beforeToken == pushTokenStr { return } beforeToken = pushTokenStr // send pushToken to service } } Task { for await stateUpdate in activity.activityStateUpdates { if stateUpdate == .active { // live activity create } } } } } } }
1
2
159
Jul ’25
Push tokens from push-to-start Live Activities require user permissions?
Just wanted to clarify some expected behaviors here. It seems that there are two distinct behaviors for Live Activity flows for freshly installed apps. When you start a Live Activity for the first time and the user hasn't yet clicked on Allow/Don't Allow in the activity interface, there are two different sequences: Starting a Live Activity locally Request a Live Activity locally via Swift Live Activity starts .pushTokenUpdates is immediately triggered, even if the Allow/Don't Allow buttons appear under the Activity UI Starting a Live Activity via push-to-start Send a push-to-start notification to launch a Live Activity Live Activity starts .pushTokenUpdates is not triggered, and .pushToken returns nil. If a user clicks on Allow in the Activity UI, only then is .pushTokenUpdates triggered.
0
3
94
2w