I'm currently seeing that OS gets a new push-to-start token immediately after receiving the first notification.
Should my server immediately invalidate the push-to-start token upon usage?
Or invalidating the push-to-start token should only be done if my iOS device gets a new one and then I have to send it back to my server.
Widgets & Live Activities
RSS for tagDiscuss how to manage and implement Widgets & Live Activities.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
WatchKit
HealthKit
WidgetKit
Background Tasks
I'm building a set of widgets that feature various emoji flags. However, when displayed in tinted mode, the emojis appear as solid white.
Is there a way to control or override the rendering mode of emojis in this context?
Any guidance would be very much appreciated. Thank you!
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.
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'**
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
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,
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
LiveActivity using colorScheme to adapt to dark mode in iOS 26 system does not work
The system keeps returning. mark, unable to switch
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!
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
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?
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
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
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!
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
WatchKit
watchOS
WidgetKit
App Intents
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?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
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.
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.
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.
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
Watch Connectivity
watchOS
Watch Complications
WidgetKit
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.
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
}
}
}
}
}
}
}
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.