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

What should your server do when apns returns a 410 Unregistered error for your token?
For our Live Activity Tokens, when we fire a payload, often apns is returning a response of 410 unregistered. Docs are saying: The device token is inactive for the specified topic. There is no need to send further pushes to the same device token, unless your application retrieves the same device token, refer to Registering your app with APNs Questions: Why does this happen? Does it only happen because the user changed their permission? Or there are other reasons? And when it does happen, what should we do about it? A. Should we keep the token on the server? Because perhaps the user will change their permission and the token becomes valid? That could leave us with lots of invalid tokens and us firing at them unnecessarily. Docs do say: Don’t retry notification responses with the error code BadDeviceToken, DeviceTokenNotForTopic, Forbidden, ExpiredToken, Unregistered, or PayloadTooLarge. B. Or should we remove the token from the server? That then requires app to re-register the token. But the problem with that is: When I went into App's settings from OS settings and toggled push notifications to on, the app was not launched into the background nor killed i.e. it requires explicit app launch by the user to re-register itself which isn't ideal... It means a user may turn on notifications from the OS settings and then assume that their push notifications should be back in business, but that won't happen if you toggle things from OS settings.
1
0
210
Nov ’25
Mac OS 26.1 Crash widget when create UIWindow
Hello, Users are reporting that widgets in my iOS app running on Mac OS are starting to crash after updating to MacOS 26.1. Everything works fine on iOS 26.1 and MacOS 15.6. The same bugs I found in iOS 26 beta 4, but then Apple fixed them in iOS 26RC and now they're back in macOS. Any suggestions? Crash report: Process: WidgetWebWidgetExt [23580] Path: /Volumes/VOLUME/*/WidgetWeb.app/PlugIns/WidgetWebWidgetExt.appex/WidgetWebWidgetExt Identifier: app.vitalek.widgetapp.web.WidgetWebExt Version: 7.5 (5796) AppVariant: 1:MacFamily20,1:18 Code Type: ARM-64 (Native) Role: unknown Parent Process: launchd [1] Coalition: app.vitalek.widgetapp.web.WidgetWebExt [28539] User ID: 501 Date/Time: 2025-11-04 11:47:19.0746 -0500 Launch Time: 2025-11-04 11:47:18.8035 -0500 Hardware Model: Mac14,6 OS Version: macOS 26.1 (25B78) Release Type: User Crash Reporter Key: 39D39455-7F69-746C-2A1D-7A6086F25541 Incident Identifier: 7AC31574-73A4-4320-B17A-C2819252EEDA Sleep/Wake UUID: 1535756C-44D8-497F-A288-07E53CD9B9E4 Time Awake Since Boot: 18000 seconds Time Since Wake: 7417 seconds System Integrity Protection: enabled Triggered by Thread: 0, Dispatch Queue: com.apple.main-thread Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6 Terminating Process: WidgetWebWidgetExt [23580] Application Specific Information: abort() called Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x1926e75b0 __pthread_kill + 8 1 libsystem_pthread.dylib 0x192721888 pthread_kill + 296 2 libsystem_c.dylib 0x192626850 abort + 124 3 libc++abi.dylib 0x1926d5858 __abort_message + 132 4 libc++abi.dylib 0x1926c44d4 demangling_terminate_handler() + 304 5 libobjc.A.dylib 0x1922f0414 _objc_terminate() + 156 6 libc++abi.dylib 0x1926d4c2c std::__terminate(void (*)()) + 16 7 libc++abi.dylib 0x1926d8394 __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) + 88 8 libc++abi.dylib 0x1926d833c __cxa_throw + 92 9 libobjc.A.dylib 0x1922e6580 objc_exception_throw + 448 10 Foundation 0x19495122c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 288 11 UIKitMacHelper 0x1b0240c80 -[UINSApplicationDelegate init] + 1348 12 UIKitMacHelper 0x1b02406d8 __41+[UINSApplicationDelegate sharedDelegate]_block_invoke + 48 13 libdispatch.dylib 0x19257eac4 _dispatch_client_callout + 16 14 libdispatch.dylib 0x192567a60 _dispatch_once_callout + 32 15 UIKitMacHelper 0x1b02405dc +[UINSApplicationDelegate sharedDelegate] + 324 16 UIKitCore 0x1ca488518 -[UIScene setTitle:] + 188 17 UIKitCore 0x1ca487e90 -[UIScene initWithSession:connectionOptions:] + 1084 18 UIKitCore 0x1cb2a6a54 -[UIWindowScene initWithSession:connectionOptions:] + 92 19 UIKitCore 0x1ca66b44c -[_UIScreenBasedWindowScene initWithScreen:session:lookupKey:] + 292 20 UIKitCore 0x1ca66aff4 +[_UIScreenBasedWindowScene _unassociatedWindowSceneForScreen:create:] + 408 21 UIKitCore 0x1cb09171c -[UIWindow _uiWindowSceneFromFBSScene:] + 704 22 UIKitCore 0x1cb0918cc -[UIWindow _initWithFrame:debugName:scene:attached:] + 92 23 UIKitCore 0x1cb091e68 -[UIWindow _initWithOrientation:] + 56 24 UIKitCore 0x1cb091ebc -[UIWindow init] + 72 25 WidgetWebWidgetExt 0x1027eb250 0x102718000 + 864848 26 WidgetWebWidgetExt 0x1027ea418 0x102718000 + 861208 27 WidgetWebWidgetExt 0x1027f5bc8 0x102718000 + 908232 28 WidgetWebWidgetExt 0x1027f4bfc 0x102718000 + 904188 29 WidgetWebWidgetExt 0x1027cf9f4 0x102718000 + 752116 30 WidgetWebWidgetExt 0x102807c20 0x102718000 + 982048 31 libdispatch.dylib 0x19257eac4 _dispatch_client_callout + 16 32 libdispatch.dylib 0x1925696e4 _dispatch_continuation_pop + 596 33 libdispatch.dylib 0x19257c800 _dispatch_source_latch_and_call + 396 34 libdispatch.dylib 0x19257b4d4 _dispatch_source_invoke + 844 35 libdispatch.dylib 0x19259c008 _dispatch_main_queue_drain.cold.5 + 592 36 libdispatch.dylib 0x192573f48 _dispatch_main_queue_drain + 180 37 libdispatch.dylib 0x192573e84 _dispatch_main_queue_callback_4CF + 44 38 CoreFoundation 0x1927ea980 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 39 CoreFoundation 0x1927bf7dc __CFRunLoopRun + 1944 40 CoreFoundation 0x19287935c _CFRunLoopRunSpecificWithOptions + 532 41 Foundation 0x194a06890 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212 42 Foundation 0x194005a50 -[NSRunLoop(NSRunLoop) run] + 64 43 libxpc.dylib 0x19240ce14 _xpc_objc_main + 668 44 libxpc.dylib 0x19241ecf8 _xpc_main + 40 45 libxpc.dylib 0x19241ecd0 xpc_bs_main + 16 46 BoardServices 0x1ac51179c +[BSServicesConfiguration activateXPCService] + 72 47 ExtensionFoundation 0x237a92710 _EXRunningExtension.resume() + 1592 48 ExtensionFoundation 0x237a911a8 _EXRunningExtension.start(withArguments:count:) + 124 49 ExtensionFoundation 0x237a88f24 EXExtensionMain(_:_:) + 668 50 Foundation 0x1940065ec NSExtensionMain + 200 51 dyld 0x192359d54 start + 7184
1
0
99
Nov ’25
How can you update a Live Activity without hitting "Allow"?
(I truly appreciate all the responses you all have written for me :bow: ) I was under the assumption that for Live Activity, in order for you to be able to update the Activity, you need an update token. And for the OS to issue you the update token, user must hit the "Allow" from the lock screen. However based on these screenshots it seems that you don't need to hit "Allow" to be able to update the Live Activity. Live Activity was updated — even without the user hitting "Allow" So now I'm wondering if: Is hitting Allow required for the update token to get issued? Or that assumption is incorrect? In our tests (when connected to Proxyman, the OS emits the update token after user hits "Allow" / "Always Allow") If you don't hit allow, are there alternate ways to update the Live Activity without having the update token? I'm guessing you could set a short stale time and then when the OS launches the app in the background you query the server and then update the Live Activity. Is that a worthy approach? I also noticed that the "The Philly Inquirer" App has 'Background App Refresh" enabled, but this happened in 2 minutes. In our architecture assessments, after reviewing Apple's docs on 'Background Processing", we didn't think of it as a viable option, because it can't guarantee if the OS is given time in the next 2 minutes or 10 hours later when the phone is getting charged again. Are any of these workarounds viable or are there alternate approaches? Our requirement is: be able to use Live Activity between 2-72hrs after app install. (I mention this because perhaps Apple may impost some restrictions for new installs) be able to update an active Live Activity within 1-2 minutes after it has began.
1
1
159
Dec ’25
Now Playing / Recently Played API
We are using the MPNowPlayingInfoCenter API to provide information to the “Now Playing” system UI. This works as expected, except that when the app is manually terminated, the information is removed from the UI. Our question is: Some apps (for example, Audible) are able to appear in the “Recently Played” section of the UI. This section seems to show a history of apps that previously provided “Now Playing” information but are not currently playing anything. We would like to know which API is used to achieve this behavior.
1
0
131
Dec ’25
iOS26 Live Activity always display in Dark Mode
Hi, We design a Live Activity for our app.We find that in iOS26 system, the widget can not display the correct system display model(Light mode or dark mode), always display with dark mode. When our app run in other system ,such as iOS 17, iOS18 ,it work fine. I find other developer had post a topic three month ago , but it seems there is not any new response about the feedback. https://developer.apple.com/forums/thread/799684?answerId=857377022#857377022 Anyone have idea? Thanks . Below is my code template: struct BroadcastLiveActivityBackgroundView: View { @Environment(\.colorScheme) var colorScheme: ColorScheme var body:some View { LinearGradient( stops: [ Gradient.Stop(color: LiveActivityColor.backgroundColors(self.colorScheme).last!, location: 0.00), Gradient.Stop(color: LiveActivityColor.backgroundColors(self.colorScheme).first!, location: 1.00), ], startPoint: UnitPoint(x: 1, y: 0), endPoint: UnitPoint(x: 0.82, y: 1.11) ) } }
1
0
144
Dec ’25
Dynamic island on a ios app
I want to make a app that indicates that the app is recording in the background using a indicator on the dynamic island or on the top of the phone screen but i can't figure it out on Xcode. Saw a guy do it by making live activities true but can't seem to find that option in background mode in capabilities. any ideas?
1
0
124
Dec ’25
Please allow the "Back to App" breadcrumb to coexist with Live Activities in Compact Mode
Subject: Request to maintain the "Status Bar Breadcrumb" visibility while Dynamic Island is active Hi, I am developing an app using ActivityKit and Dynamic Island. I've noticed a significant UX regression regarding the system status bar behavior. Current Behavior: When a Live Activity is active in the Dynamic Island (specifically in the compactLeading and compactTrailing presentation), the system automatically hides the "Back to [Previous App]" breadcrumb button (the small arrow and app name) in the top-left corner of the status bar. This breadcrumb only reappears when the Live Activity switches to the minimal presentation or is dismissed. The Issue: This behavior makes multitasking cumbersome for users. For example, if a user navigates from Safari to my app and then locks the screen or goes to Home, they expect the "Back to Safari" button to remain accessible. However, because my app's Live Activity is running in the Dynamic Island, the OS removes this navigation shortcut, forcing users to use the app switcher instead. Why this should be changed: Screen Real Estate: On larger devices (e.g., iPhone 15/16 Pro Max), there is significant whitespace in the top-left corner between the time and the Dynamic Island's leading edge. The breadcrumb could easily fit there without overlapping the Live Activity content. Inconsistent UX: Users are confused why the navigation button disappears solely because a background activity is running. Request: Please consider updating the status bar layout logic to allow the "Back to App" breadcrumb to remain visible if there is no physical overlap with the compactLeading view of the Dynamic Island. Thank you.
1
0
92
2w
Watch Face sharing stopped working on watchOS 26 (CLKWatchFaceLibrary)
Since watchOS 26, watch face sharing has stopped working completely. I tested the following: Sharing via CLKWatchFaceLibrary Other public APIs Sharing via iMessage In all cases, the watch face cannot be reinstalled after being shared. This issue is not limited to my app. Large third-party apps such as Facer and other major watch face platforms are also affected, which suggests this is a system-level change or bug. Everything worked correctly before watchOS 26. Has Apple officially acknowledged this issue? Is there a recommended place to report or track this bug?
1
0
100
1w
Widget - App may push the list view twice when launched from widget
Issue Description: Tapping the app widget sometimes triggers the Universal Link twice, causing duplicate navigation or actions within the app Steps to Reproduce: Add the app widget to the home screen Tap the widget to open the app via the Universal Link Observe that the Universal Link is sometimes fired twice Expected Behavior: Tapping the widget should trigger the Universal Link only once. Actual Behavior: Universal Link is triggered twice, causing duplicate navigation or actions.
1
0
46
6d
Home screen Widget with dynamic options for configuration via App Intent - Slow
I am building a widget with configurable options (dynamic option) where the options are pull from api (ultimately the options are return from a server, but during my development, the response is constructed on the fly from locally). Right now, I am able to display the widget and able to pull out the widget configuration screen where I can choose my config option . I am constantly having an issue where the loading the available options when selected a particular option (e.g. Category) and display them on the UI. Sometime, when I tap on the option "Category" and the loading indicator keeps spinning for while before it can populate the list of topics (return from methods in NewsCategoryQuery struct via fetchCategoriesFromAPI ). Notice that I already made my fetchCategoriesFromAPI call to return the result on the fly and however the widget configuration UI stills take a very long time to display the result. Even worst, the loading (loading indicator keep spinning) sometime will just kill itself after a while and my guess there are some time threshold where the widget extension or app intent is allow to run, not sure on this? My questions: How can I improve the loading time to populate the dynamic options in widget configuration via App Intent Here is my sample code for my current setup struct NewsFeedConfigurationIntent: AppIntent, WidgetConfigurationIntent { static let title: LocalizedStringResource = "Configure News Topic Options" static let description = IntentDescription("Select a topic for your news.") @Parameter(title: "Category", default: nil) var category: NewsCategory? } struct NewsCategory: AppEntity, Identifiable { let id: String let code: String let name: String static let typeDisplayRepresentation: TypeDisplayRepresentation = "News Topic" static let defaultQuery = NewsCategoryQuery() var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: LocalizedStringResource(stringLiteral: name)) } } struct NewsCategoryQuery: EntityQuery { func entities(for identifiers: [NewsCategory.ID]) async throws -> [NewsCategory] { let categories = fetchCategoriesFromAPI() return categories.filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [NewsCategory] { fetchCategoriesFromAPI() } } func fetchCategoriesFromAPI() -> [NewsCategory] { let list = [ "TopicA", "TopicB", "TopicC", ....... ] return list.map { item in NewsCategory(id: item, code: item, name: item.capitalized) } }
0
0
152
Apr ’25
How to Display Multiple Media Contents in the Now Playing Control Center?
Hello everyone, I am currently developing a media playback app and want to achieve the following functionality: Display multiple media contents in the Now Playing control center, instead of just showing the currently playing one. Allow users to select and switch between different contents, such as videos, music, etc., from the control center. However, I have encountered some issues: Although I have integrated the Now Playing control center, it only displays the current media being played. I would like to display multiple selectable media contents (such as a video list, music list, etc.) in the control center, similar to what is done by some media player apps, and allow users to switch between them. I’ve tried the following methods: Using MPNowPlayingInfoCenter to update the current playing media information. Attempting to set MPNowPlayingInfoPropertyPlaybackQueueCount to show multiple items in the queue, but it doesn’t seem to work. Can anyone provide guidance on how to display multiple media contents in the Now Playing control center? Any experienced developers who could share their insights or suggestions would be greatly appreciated! Thank you very much for your help and feedback!
0
0
141
Apr ’25
Live Activity - ActivityState - case .dismissed
Hi everyone, I'm working with Live Activities using the ActivityKit(Activity), and I'm trying to find a way to detect when a user manually dismisses a Live Activity by swiping it away — either from the Lock Screen or the Dynamic Island. Currently, when a Live Activity ends, the activityState changes to .dismissed, which is defined as: /// The Live Activity ended and is no longer visible because a person or the system removed it. case dismissed This doesn’t allow me to determine whether the dismissal was triggered by the user or by the system. Is there any way — either through ActivityState, notifications, or another approach — to distinguish if a Live Activity was manually dismissed by the user vs. ended by the system? Thanks in advance!
0
0
176
Apr ’25
Help getting elements from SwiftData in AppIntent for widget
Hello, I am trying to get the elements from my SwiftData databse in the configuration for my widget. The SwiftData model is the following one: @Model class CountdownEvent { @Attribute(.unique) var id: UUID var title: String var date: Date @Attribute(.externalStorage) var image: Data init(id: UUID, title: String, date: Date, image: Data) { self.id = id self.title = title self.date = date self.image = image } } And, so far, I have tried the following thing: AppIntent.swift struct ConfigurationAppIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource { "Configuration" } static var description: IntentDescription { "This is an example widget." } // An example configurable parameter. @Parameter(title: "Countdown") var countdown: CountdownEntity? } Countdowns.swift, this is the file with the widget view struct Provider: AppIntentTimelineProvider { func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) } func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { SimpleEntry(date: Date(), configuration: configuration) } func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> { var entries: [SimpleEntry] = [] // Generate a timeline consisting of five entries an hour apart, starting from the current date. let currentDate = Date() for hourOffset in 0 ..< 5 { let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! let entry = SimpleEntry(date: entryDate, configuration: configuration) entries.append(entry) } return Timeline(entries: entries, policy: .atEnd) } // func relevances() async -> WidgetRelevances<ConfigurationAppIntent> { // // Generate a list containing the contexts this widget is relevant in. // } } struct SimpleEntry: TimelineEntry { let date: Date let configuration: ConfigurationAppIntent } struct CountdownsEntryView : View { var entry: Provider.Entry var body: some View { VStack { Text("Time:") Text(entry.date, style: .time) Text("Title:") Text(entry.configuration.countdown?.title ?? "Default") } } } struct Countdowns: Widget { let kind: String = "Countdowns" var body: some WidgetConfiguration { AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in CountdownsEntryView(entry: entry) .containerBackground(.fill.tertiary, for: .widget) } } } CountdownEntity.swift, the file for the AppEntity and EntityQuery structs struct CountdownEntity: AppEntity, Identifiable { var id: UUID var title: String var date: Date var image: Data var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(title)") } static var defaultQuery = CountdownQuery() static var typeDisplayRepresentation: TypeDisplayRepresentation = "Countdown" init(id: UUID, title: String, date: Date, image: Data) { self.id = id self.title = title self.date = date self.image = image } init(id: UUID, title: String, date: Date) { self.id = id self.title = title self.date = date self.image = Data() } init(countdown: CountdownEvent) { self.id = countdown.id self.title = countdown.title self.date = countdown.date self.image = countdown.image } } struct CountdownQuery: EntityQuery { typealias Entity = CountdownEntity static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Countdown Event") static var defaultQuery = CountdownQuery() @Environment(\.modelContext) private var modelContext // Warning here: Stored property '_modelContext' of 'Sendable'-conforming struct 'CountdownQuery' has non-sendable type 'Environment<ModelContext>'; this is an error in the Swift 6 language mode func entities(for identifiers: [UUID]) async throws -> [CountdownEntity] { let countdownEvents = getAllEvents(modelContext: modelContext) return countdownEvents.map { event in return CountdownEntity(id: event.id, title: event.title, date: event.date, image: event.image) } } func suggestedEntities() async throws -> [CountdownEntity] { // Return some suggested entities or an empty array return [] } } CountdownsManager.swift, this one just has the function that gets the array of countdowns func getAllEvents(modelContext: ModelContext) -> [CountdownEvent] { let descriptor = FetchDescriptor<CountdownEvent>() do { let allEvents = try modelContext.fetch(descriptor) return allEvents } catch { print("Error fetching events: \(error)") return [] } } I have installed it in my phone and when I try to edit the widget, it doesn't show me any of the elements I have created in the app, just a loading dropdown for half a second: What am I missing here?
0
0
136
Apr ’25
communication between live activity and main app
I found the live activity process cannot write to the app group and FileManger, can only read the app group. When I write using FileManager in a live activity process, the console prompts me with a permission error. When I write using UserDefault(suit:) in the live activity process, I read a null value in the main app. Is this the case for real-time event design? I haven’t seen any documentation mentioning this. Does anyone know, thank you very much.
0
0
109
May ’25
push-to-start notification does not reliably result in a new push-to-update token on the pushTokenUpdates async sequence
I've noticed that the when starting live activities via a remote push-to-start notification, the live activity widget consistently succeeds in displaying on the lock screen. However push-to-update token is not always received by the task observing the pushTokenUpdates async-sequence. Task { print("listening for pushTokenUpdates") for await pushToken in activity.pushTokenUpdates { let token = pushToken.map {String(format: "%02x", $0)}.joined() print("Push token: \(token)") } } The log will print "listening for pushTokenUpdates" however occasionally the "Push token: ___" line will not be present even when the widget has displayed on screen. This happens even if the "allow" button has been selected on live activities for that app. The inconsistent behavior leads me to believe there is an issue at the ActivityKit level. Would appreciate any feedback in debugging this!
0
1
175
May ’25