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
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
When using the ManagedSettings API to block apps everything is blocked as expected (the app itself, Notifications, Live Activities on the Lock Screen etc) except for Compact Live Activities of those apps (that are shown in the Dynamic Island). I feel the expected behavior would be to block also the Compact Live Activities.
Our use case:
In Spoilerblock we want to prevent users from being exposed to spoilers before they've had time to watch for example a sports game.
Current workaround:
Right now the best we can do is to ask the user to disable Live Activities for apps that could expose results, to not risk being exposed to a spoiler.
Hi,
My iOS app's home screen widget content was implemented to base on the preferred language of my main app (e.g. my app has the following preferred language options with this order English, Japanese, Traditional Chinese, Korean, Simplify Chinese).
Say the main app is currently using English as their preferred language, I can change the preferred language in the iOS Settings -> Apps -> My App -> Preferred Language.
My widget's content will respect to the preferred language option that I selected with only exception if I switch back to English language and my Widget's content won't get updated. The Main app content is always update with respect to the selected preferred language.
My app and widget is working without any issue in iOS 18.
Other things that I had discovered during my testing under iOS 26, the "first" language appeared in my preferred language always being the issue (e.g. if the first language is Japanese , once I change to other languages and than switch back to Japanese, my widget content won't respect to this but the main app content are ok).
Any one has a similar issues regarding the preferred language?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
Internationalization
Localization
We have some AppIntents we are POCing and when we make a Release build, they no longer appear in the system.
These AppIntents live in a Framework compiled and linked with the core app.
We believe that this is related to Mergable Libraries. We have confirmed that the meta data for the framework still contains a list of all of the actions and their mangled symbols.
The mangled symbols however now live in the app binary (confirmed by building Release with DEBUG_INFORMATION_FORMAT = dwarf)
If we move the AppIntent code into the app target, things once again work as expected.
Is there a flag we need to set, or is moving the code into the app target the only workaround?
Thank you!
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
LiveActivity using colorScheme to adapt to dark mode in iOS 26 system does not work
The system keeps returning. mark, unable to switch
Hi everyone, I'm using an app group to share data between iOS and it's watch companion app.
I ensured that is has the same identifier in Signing & Capabilities and in the .entitlements files.
Here is the UserDefaults part:
class UserDefaultsManager {
private let suitName = "group.com.sanjeevbalakrishnan.Test"
public func saveItems(_ items: [ItemDTO]) {
print("Save \(items.count) items to shared defaults")
let defaults = UserDefaults(suiteName: suitName)
let data = try? JSONEncoder().encode(items)
defaults?.set(data, forKey: "items")
}
public func loadItems() -> [ItemDTO] {
let defaults = UserDefaults(suiteName: suitName)
print(defaults)
guard let data = defaults?.data(forKey: "items") else {
print("watchOS received data is empty")
return []
}
let items = [ItemDTO].from(data: data)
print("Load \(items.count) items from user defaults")
return items
}
}
For testing I called loadItems after saveItems on iOS app and it returned items. However, on watchOS app it always returns empty array.
What do I need to consider?
Thanks.
Best regards
Sanjeev
I have an app that has a Core Data store for dates with descriptions that I'd like to present in a widget with countdown calculations. In the app I have a button that just equates an active calculation to the currently selected item in the database (using an EnvironmentObject). I gather I can't use this mechanism inside a widget, right?
The user could put tons of items into the database - so I'm sure I don't want to have an editable widget allowing them to pick. I suppose I could create an intent and allow an independent entering from the app - but that seems rather user hostile since they've already entered it for the app - and I'm still trying to support iOS15 which doesn't support that.
I did create an App Group and have the Core Data store available from within the widget, but I don't see how to allow the user to choose which date is active. I also want multiple widgets to be able to point to different dates. Any help would be appreciated. Thanks!
When we use AppIntents to configure WidgetKit complications, the description we provide in IntentRecommendation is ignored after applying a .watchface file that includes those intent configurations. In the Watch app, under Complications, the labels shown next to each slot do not match the actual complications on the face—they appear to be the first strings returned by recommendations() rather than the selected intent configuration.
Steps to Reproduce
Create an AppIntent used by a WidgetKit complication (e.g., .accessoryRectangular).
Provide multiple intent recommendations with distinct descriptions:
struct SampleIntent: AppIntent {
static var title: LocalizedStringResource = "Sample"
static var description = IntentDescription("Sample data")
@Parameter(title: "Mode") var mode: String
static func recommendations() -> [IntentRecommendation<Self>] {
[
.init(intent: .init(mode: "A"), description: "Complication A"),
.init(intent: .init(mode: "B"), description: "Complication B"),
.init(intent: .init(mode: "C"), description: "Complication C")
]
}
func perform() async throws -> some IntentResult { .result() }
}
Add two of these complications to a Modular Duo face (or any face that supports multiple slots), each with different intent configurations (e.g., A in one slot, B in another).
Export/share the face to a .watchface file and apply it on another device.
Open the Watch app → the chosen face → Complications.
Expected
Each slot’s label in Complications reflects the specific intent configuration on the face (e.g., “Complication A”, “Complication B”), matching what the complication actually renders.
Actual
The labels under Complications do not match the visible complications. Instead, the strings shown look like the first N items from recommendations(), regardless of which configurations are used in each slot.
Notes
The complications themselves render correctly on-watch; the issue is the names/labels displayed in the Watch app UI after applying a .watchface.
Filed Feedback: FB20915258
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
watchOS
Watch Complications
WidgetKit
App Intents
Hey!
I'm working on enabling remotely started live activities. I'm running into 2 crashes:
Upon initializing ActivityAuthorizationInfo
Upon calling Activity<...>.activities array
Both stack traces look like this:
0 libsystem_kernel.dylib +0xce0 _mach_msg2_trap
1 libsystem_kernel.dylib +0x4398 _mach_msg2_internal
2 libsystem_kernel.dylib +0x42b4 _mach_msg_overwrite
3 libsystem_kernel.dylib +0x40fc _mach_msg
4 libdispatch.dylib +0x1cc04 __dispatch_mach_send_and_wait_for_reply
5 libdispatch.dylib +0x1cfa4 _dispatch_mach_send_with_result_and_wait_for_reply
6 libxpc.dylib +0x107ec _xpc_connection_send_message_with_reply_sync
7 BoardServices +0xaea8 -[BSXPCServiceConnectionMessage _sendWithMode:]
8 BoardServices +0x17938 -[BSXPCServiceConnectionMessage sendSynchronouslyWithError:]
9 BoardServices +0xeef0 ___71+[BSXPCServiceConnectionProxy createImplementationOfProtocol:forClass:]_block_invoke
They happen to a limited number of users, but not insignificant. Most are on iOS 18.6.2 and iOS 26.1, but there are others in the mix. I don't have a repro myself. It looks like the main thread gets blocked after we receive no response from these ActivityKit APIs. Both of these are called inside application:didFinishLaunchingWithOptions:.
For ActivityAuthorizationInfo, we need the app to communicate with the server whether the user has live activities enabled; hence, calling this object's init as early as possible in the app.
For activities array, I'd like to do some logging whenever the live activity is started or ended (for example, if activities array no longer contains any activities, we can log the activity as dismissed). For this logging to happen, as far as I understand, it has to happen inside didFinishLaunchingWithOptions since this is the only method being called upon the terminated app receiving background runtime when the live activity starts/ends remotely.
After some research, one potential reason is ActivityKit APIs are just not ready to return values via xpc connection at app startup, so moving these methods to applicationDidBecomeActive could resolve the problem. That's fine for ActivityAuthorizationInfo init, but for accessing activities, there is no other place in the lifecycle to see if an activity has been dismissed (especially in the scenario where app is terminated, so we get only 30 seconds ish of background runtime).
Curious if anyone has run into this or has any insights into ActivityKit API behavior.
Hey,
I successfully set my app to use alarm kit, alarm is showing up and everything, but I noticed that the sound I created (mp3 files, less than 30 sec each) only plays once, does not repeat itself. Is that intended?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
I’m implementing a Live Activity that shows some text and a button.
When the user taps the button, I want to open the host app.
What I’ve done so far:
Implemented a LiveActivityIntent to handle the button tap.
The intent is triggered successfully. However, the app does not open by using deep link/universal app link.
From what I can tell, LiveActivityIntent seems limited to system/background execution and doesn’t bring the app to the foreground.
Questions:
Is it possible for a LiveActivityIntent to open the app?
Is this behavior a documented/intentional limitation?
If not supported, is using a Universal Link or deep link the recommended solution for opening the app from a Live Activity button?
Any official clarification or recommended best practice would be helpful.
I'm building out a live activity that has a button which is meant to update the content state of the Live Activity. It calls a LiveActivityIntent that runs in the app process.
The push server starts my live activity and the buttons work just fine. I pass the push token back to the server for further updates and when the next update is pushed by the server the buttons no longer work. With the debugger I'm able to verify the app intent code runs and passes the updated state to the activity. However the activity never updates or re-renders. There are no logs in Xcode or Console.app that indicates what the issue could be or that the update is ignored.
I have also tried adding the frequent updates key to my plist with no change.
I'm updating the live activity in the LiveActivityIntent like this:
public func perform() async throws -> some IntentResult {
let activities = Activity<WidgetExtensionAttributes>.activities
for activity in activities {
let currentState = activity.content.state
let currentIndex = currentState.pageIndex ?? 0
let maxIndex = max(0, currentState.items.count - 1)
let newIndex: Int
if forward {
newIndex = min(currentIndex + 1, maxIndex)
} else {
newIndex = max(currentIndex - 1, 0)
}
var newState = currentState
newState.pageIndex = newIndex
await activity.update(
ActivityContent(
state: newState,
staleDate: nil
),
alertConfiguration: nil,
timestamp: Date()
)
}
return .result()
}
To sum up:
Push to start -> tap button on activity -> All good!
Push to start -> push update -> tap button -> No good...
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
APNS
Intents
App Intents
ActivityKit
Hi there,
I'm adding a new widget using the new WidgetConfigurationIntent which takes a number of parameters, including one which conforms to AppEntity. It is defined as an optional.
When the user is configuring the widget, after one of the suggested entities is chosen, there is no way to return to a state where this value is nil. Is this possible? I'd like the user to be able to select "None" for this parameter. For now, I'm using a bool to determine whether the AppEntity parameter is used.
Thanks!
I noticed that with iOS 18, when adding a widget to the Control Center, there is now some "grouping system". I'm interested in the Capture group, which contains native widgets from Apple as well as third party apps like Instagram and Blackmagic cam, widgets in this group open the camera. My widget also opens the camera in my app, how can I add it to this group?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
SwiftUI
WidgetKit
App Intents
Live Activity Start Token not generating after certain days of usage. We have implemented Live Activity feature where the initial activity is launched by our backend. But to start that first live activity I need push to start token which is generating for few days but all of sudden after certain days it stops generating. Currently we are in development phase so we test it on multiple devices and multiple time we are doing install and uninstall.
STEPS TO REPRODUCE
Install the app
Start token gets generated which is sent to our server
After certain duration server sends the first live activity using that token
user opens the app then we receive the updated token and send that token to server
server uses that updated token to further update the live activity.
All this works fine. But after a week of usage we are observing that we stop getting start token from APNS. Not sure where exactly the thing is breaking. We have tried with different devices and different bundle identifiers but behaviour is same for all.
func generateStartToken() {
Task.detached { [weak self] in
guard let self else { return }
await self.observeActivityPushTokenAndState()
for await data in ActivityKit.Activity<LiveActivityAttribute>.pushToStartTokenUpdates {
let token = data.map { String(format: "%02x", $0) }.joined()
print("Activity Start token: ", token)
}
}
}
func observeActivityPushTokenAndState() {
Task.detached {
for await activity in ActivityKit.Activity<LiveActivityAttribute>.activityUpdates {
Task {
for await tokenData in activity.pushTokenUpdates {
let updatedToken = tokenData.map { String(format: "%02x", $0) }.joined()
print("Activity Update token: ", updatedToken)
}
}
Task {
for await content in activity.contentUpdates {
let updatedContent = content.state
print("Activity Updated: ", updatedContent)
}
}
}
}
}
I have a question about how a watch widget can access HealthKit data. Does it, as the large model mentioned, share data through an App Group, or does it directly access the HealthStore?
Hi, I have a class project I am working on (with a due date tomorrow, unfortunately RIP to me). But I have made my project about adding accessibility to a Unity game. I've successfully added apple unity core and accessibility plugins to my project, and my project builds. But I have simple text nodes and buttons and they aren't accessible with voiceover once I build/export my game and test. I am only building for MacOS right now (for the assignment).
I don't have too much experience with Unity, but I am relatively experienced with accessibility (even formerly an intern and contractor at Apple for accessibility). So I wonder if I am just using Unity incorrectly? Perhaps I've done something to my build process (or haven't done something I should)? I've attached a photo of what my dev environment looks like in Unity, I've focused a text node (on the left) and on the right are my AccessibilityNode settings.
Any help would be awesome, even if I don't make my deadline tomorrow... :*(
Project repo is here, if it is helpful: https://github.com/frankelavsky/PGD_final_project
Thanks!
I am seeing a really weird behavior with Live Activities. The Live Activity is always appearing on the simulator. However the Live Activity is only appearing on my physical device when there is no other widget in the widget bundle shown below.
@main
struct HoerspielWidgetsBundle: WidgetBundle {
var body: some Widget {
// Uncomment the line below and the Live Activity will no longer appear
// UpNextWidget()
PlaybackLiveActivity()
}
}
Annotating that var with @WidgetBundle has no effect.
There are no logs indicating an error, the function to request a Live Activity does not throw and the status of the activity is active.
Both the widget and the Live Activity are working fine otherwise. NSSupportsLiveActivities is set to true in the correct Info.plist file. I am not running any beta software and the physical iPhone is on the newest version (iOS 18.5). Using the template when adding a new target in Xcode, I was able to set up a similar app where the Live Activity works as expected.
I am really at a loss here which additional information I should provide or how this issue can be resolved.
Thank you for your help.
Hello forum,
I want to keep my app running in the background after user swaps up, for the purpose of workout tracking.
start up the task and continuously receipt GPS updates
process the location data
show the data on a live activity
Two examples
Strava
paddlelogger
Question:
Does this mean, these two apps would just pause when the .backgroundTimeRemaining becomes 0?
How does a workout app "work" in background mode, do I need to handle budget running out?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
Core Location
Maps and Location
Background Tasks
Hi, I’m using SwiftData with an @Observable DatabaseManager class that is shared between my app and a widget. This class is located inside a Swift package and looks roughly like this:
public final class DatabaseManager {
public static let shared = DatabaseManager()
private init() {
let groupID = "group.com.yourcompany.myApp"
let config = ModelConfiguration(groupContainer: .identifier(groupID))
let c = try! ModelContainer(for: MyModel.self, configurations: config)
self.container = c
self.modelContext = c.mainContext
}
public private(set) var container: ModelContainer
public private(set) var modelContext: ModelContext
}
In the main app, I inject the container and context like this:
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(DatabaseManager.shared.container)
.modelContext(DatabaseManager.shared.modelContext)
}
}
}
Both the widget and the main app import the same package, and both use DatabaseManager.shared for reading and writing objects.
The problem:
When the widget updates an object using an AppIntent, the change is not reflected in the main app unless I fully terminate and relaunch it. If I just bring the app back to the foreground, it still shows stale data.
Is there a recommended way to make the main app observe or reload SwiftData changes that were made in the widget (via the same shared app group and container)? I’m already using .modelContainer(...) and .modelContext(...) in the app, and everything else works fine — it’s just the syncing that doesn’t happen unless I force-relaunch the app.
Thanks!