Hello,
I am trying to test a concept of a timer stopwatch with Live Activities and integrating buttons like Pause/Resume. When the stopwatch starts, a new Live Activity is created.
The stopwatch is managed by the ViewModel, which has functions like start(), pause(), resume(), reset(), and also startLiveActivity(), etc.
It uses @AppStorage to store keys like stopWatchModeRaw values, startTimeInterval, etc.
The Live Activity state is stored here in the view model using:
private var currentActivity: Activity? = nil
The Live Activity is started using:
private func startActivity() async {
guard currentActivity == nil, Activity<StopwatchAttributes>.activities.isEmpty else {
if currentActivity == nil {
findAndAssignExistingActivity()
await updateActivity()
}
return
}
let attributes = StopwatchAttributes()
let state = StopwatchAttributes.ContentState(
.... pass in the content state variables ....
)
let content = ActivityContent(state: state, staleDate: nil)
do {
let activity = try Activity<StopwatchAttributes>.request(
attributes: attributes,
content: content,
pushType: nil
)
// Store the activity instance
self.currentActivity = activity
} catch {
print("Error requesting Live Activity: \(error.localizedDescription)")
}
}
and FindAndAssignExistingAcivity does:
private func findAndAssignExistingActivity() {
if let existingActivity = findActivity(), existingActivity.activityState == .active || existingActivity.activityState == .stale {
print("Found existing activity on launch: \(existingActivity.id)")
self.currentActivity = existingActivity
} else {
print("No existing activity found on launch.")
self.currentActivity = nil
}
}
UpdateActivity if the activity exists with a guard statement, and then update the activity. This is also used when the user taps Pause in the Stopwatch.
The main issue I am facing is with the PauseIntent, it can't find the Live Activity and will always exit at that guard statement.
struct PauseIntent: AppIntent {
static var title: LocalizedStringResource = "Pause Stopwatch"
func perform() async throws -> some IntentResult {
guard let defaults = UserDefaults(suiteName: appGroupID) else {
return .result() // Simple failure
}
let currentModeRaw = defaults.integer(forKey: "stopwatchModeRawValue")
let currentMode = StopwatchMode(rawValue: currentModeRaw) ?? .reset
let startTimeInterval = defaults.double(forKey: "startTimeInterval") // TimeInterval when current running segment started
let accumulatedTime = defaults.double(forKey: "accumulatedTime")
guard let activity = Activity<StopwatchAttributes>.activities.first else {
Self.logger.error("PauseIntent EXIT: No Live Activity found to update. (Activity<StopwatchAttributes>.activities is empty)")
return .result() // EXITING HERE, No Live Activity Found, there was nothing found to update... -> It always exits here
}
followed by rest of the code to update the state of the live activity, but it never executes because the
activity = Activity.activities.first always returns false.
What seems to be the issue?
1 .Is the method wrong to check for the live activity before attempting to Pause?
2. Can the Live Activity actually Pause the Stopwatch Timer in the main App since the Live Activity is actually a Widget Extension and not the App itself, so it cannot see the data directly?
App Intents
RSS for tagExtend your app’s custom functionality to support system-level services, like Siri and the Shortcuts app.
Posts under App Intents tag
168 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi Community,
I'm new on Siri intents and I'm trying to introduce into my App a Siri Intent for Car Commands. The objective is to list into the Apple Maps the Car list of my App. Currently I've created my own target with its corresponding IntentHandlings, but in the .intentdefinition file of my App, I'm not able to find the List Car Intent.
https://developer.apple.com/documentation/sirikit/car-commands
Do I need some auth?
Also I share my info.plist from the IntentExtension.
Thank you very much,
David.
Topic:
App & System Services
SubTopic:
Automation & Scripting
Tags:
Swift
SiriKit
Intents
App Intents
Hi!
In neither Xcode 16.2 beta 3 nor Xcode 16.2 I am able to get App Shortcuts Preview to recognise my Shortcuts. In either supported language I always get "No Matching Intent" as the result.
Flexible matching is enabled, minimum deployment target is iOS 18. The Shortcut phrases do work in the simulator and on device.
Is this a known issue or am I missing something?
I am building a CarPlay navigation app and I would like it to be as hands free as possible.
I need a better understanding of how Siri can work with CarPlay and if the direction I need to go is using Intents or App Shortcuts.
My goal is to be able to have the user speak to Siri and do things like "open settings" or "zoom in map" and then call a func in my app to do what the user is asking.
Does CarPlay support this? Do I need to use App Intents or App Shortcuts or something else?
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?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
SwiftUI
WidgetKit
App Intents
SwiftData
I'd like to display a list of items to disambiguate for a fulltext search intent. Using the Apple AppIntentsSampleApp, I added TrailSearch.swift:
import AppIntents
@AssistantIntent(schema: .system.search)
struct TrailSearch: AppIntent {
static let title: LocalizedStringResource = "Search Trail"
static let description = IntentDescription("Search trail by name.",
categoryName: "Discover",
resultValueName: "Trail")
@Parameter(title: "Trail")
var criteria: StringSearchCriteria
func perform() async throws -> some IntentResult & ReturnsValue<TrailEntity> {
if criteria.term.isEmpty {
throw $criteria.needsValueError(IntentDialog("need value"))
}
let trails = TrailDataManager.shared.trails { trail in
trail.name.contains(criteria.term)
}
if trails.count > 1 {
throw $criteria.needsDisambiguationError(among: trails.map { StringSearchCriteria(term: $0.name) })
} else if let firstTrail = trails.first {
return .result(value: TrailEntity(trail: firstTrail))
}
throw $criteria.needsValueError(IntentDialog("Nothing found"))
}
}
Now when I type "trail" which matches several trails and thus lets us enter the disambiguation code path, the Shortcut app just displays the dialog title but no disambiguation items to pick from.
Is this by design or a bug?
(filed as FB17412220)
Topic:
App & System Services
SubTopic:
Automation & Scripting
Tags:
Siri and Voice
Shortcuts
Intents
App Intents
I am new to the idea of Siri Shortcuts and App Intents. What I want to do is use Siri to run a function in my app.
Such as saying to Siri Zoom in map and that will then call a function in my app where I can zoom in the map. Similarly, I could say Zoom out map and it would call a function to zoom out my map.
I do not need to share any sort of shortcut with the Shortcuts app.
Can someone please point me in the right direction for what type of intents I need to use for this?
While playing around with AppShortcuts I've been encountering some problems around getting the invocation phrase detected and/or the parameter get recognized after invocation phrase via Siri. I've found some solutions or explanations here in other posts (Siri not recognizing the parameter in the phrase & Inform iOS about AppShortcutsProvider), but I still have one issue and it's about consistency.
For context, I've defined the parameter to be an AppEntity with it's respective query conforming to the EntityStringQuery Protocol in order to be able to fetch entities with the string given by Siri
struct AnIntent: AppIntent {
// other parts hidden for clarity
@Parameter
var entity: ModelEntity
}
For an invocation phrase akin to "Do something with in ", if the user uses the phrase with a entity previously donated via suggestedEntities() the AppShortcut get executed without problems. If the user uses a phrase with no parameter, like "do something with ", if the user gets asked to input the missing parameter and inputs one, it may or may not get recognized and be asked to input a parameter again, like in a loop. This happens even if the parameter given is one that was donated.
I've found that when this happens the entities(matching string: String) function in the EntityQuery doesn't get called. The input can be of one word or sometimes two and it will not be called. So in other words entities(matching string: String) does not get called on every user parameter input
Is this behavior correct?
Do parameters have some restrictions on length or anything?
Does Siri shows the user suggested entities when asked for entity input? It doesn't on my end.
Additional question related to AppShortcuts:
On AppShortcut definition, where the summary inside the parameter presentation is used? I see that it was defined in the AppIntentsSampleApp for the GetTrailInfo Intent but didn't find where it was used
Topic:
App & System Services
SubTopic:
Automation & Scripting
Tags:
Siri and Voice
Shortcuts
App Intents
Is there any way to obtain the ControlWidget installed by user, I use WidgetCenter.shared.getCurrentConfigurations cannot work
I need to have a dynamic parameter for Shortcuts, so a person can say something like
Hey Siri, order a pizza with
The parameter code in the appIntent is
@Parameter(title: "Title")
var itemName: String
In the Shortcut I use:
AppShortcut(
intent: NewItemIntent(),
phrases: [
"order \(\.$itemName) using \(.applicationName)"
],
shortTitle: "Order Item",
systemImageName: "sparkles"
)
When I call it "hey Siri, order pizza using ***" where pizza should be passed via the parameter then handed off to the appintent. However, it ignores the spoken parameter in lieu of putting up a dialog asking "What's the name?" I can say "pizza" and it now works. How can I pick up the parameter without having to go to that second step as the code implies?
I'm developing an AppIntent with a Duration parameter, the definition looks like this:
@Parameter(title: "Duration", description: "Time entry duration")
var duration: Measurement<UnitDuration>
When I run this AppIntent using Siri voice command (by a shortcut) the system asks for the duration value, however when I try to say "1 hour 10 minutes" the "hour" component is ignored, in the AppIntent's perform() method I see only the minutes set (so in this case only 10 minutes).
Is there any way to use the Duration type for this type of natural language input?
When I try to set only 10 minutues, or 1 hour separately it works, just the combination of these two fails.
Thank you
I have a custom intent. When my app is unable to complete the resolution of a parameter within the app extension, I need to be able to continue within the app. I am unable to figure out what the correct objective C syntax is to enable the execution to continue with the app. Here is what I have tried:
completion([[PickWoodIntentResponse init] initWithCode:PickWoodIntentResponseCodeContinueInApp userActivity:nil]);
This results in the following error:
Implicit conversion from enumeration type 'enum PickWoodIntentResponseCode' to different enumeration type 'INAnswerCallIntentResponseCode' (aka 'enum INAnswerCallIntentResponseCode')
I have no idea why it is referring to the enum type of 'INAnswerCallIntentResponseCode' which is unrelated to my app.
I have also tried:
PickWoodIntentResponse *response = [[PickWoodIntentResponse init] initWithCode:PickWoodIntentResponseCodeContinueInApp userActivity:nil];
completion(response);
but that results in 2 errors:
Implicit conversion from enumeration type 'enum PickWoodIntentResponseCode' to different enumeration type 'INAnswerCallIntentResponseCode' (aka 'enum INAnswerCallIntentResponseCode')
and
Incompatible pointer types passing 'PickWoodIntentResponse *' to parameter of type 'INStringResolutionResult *'
The relevant autogenerated code provided to me with the creation of my intent is as follows:
@class PickWoodIntentResponse;
@protocol PickWoodIntentHandling <NSObject>
- (void)resolveVarietyForPickWood:(PickWoodIntent *)intent withCompletion:(void (^)(INStringResolutionResult *resolutionResult))completion NS_SWIFT_NAME(resolveVariety(for:with:)) API_AVAILABLE(ios(13.0), macos(11.0), watchos(6.0));
@end
typedef NS_ENUM(NSInteger, PickWoodIntentResponseCode) {
PickWoodIntentResponseCodeUnspecified = 0,
PickWoodIntentResponseCodeReady,
PickWoodIntentResponseCodeContinueInApp,
PickWoodIntentResponseCodeInProgress,
PickWoodIntentResponseCodeSuccess,
PickWoodIntentResponseCodeFailure,
PickWoodIntentResponseCodeFailureRequiringAppLaunch
}
@interface PickWoodIntentResponse : INIntentResponse
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCode:(PickWoodIntentResponseCode)code userActivity:(nullable NSUserActivity *)userActivity NS_DESIGNATED_INITIALIZER;
@property (readonly, NS_NONATOMIC_IOSONLY) PickWoodIntentResponseCode code;
@end
Am I overlooking something? What would be the proper syntax to have within the completion block to satisfy the compiler?
I have an iOS app that connects to a server running on macOS by leveraging NWListener & NWBrowser. It also makes use of the peerToPeer functionality / AWDL offered via the Network framework. This works great in the iOS app. Now I would like to add support for Shortcuts / App Intents in general.
The NWConnection on its own is also working great in the App Intent, but only if I provide the host/port manually, which means I can't use the peer to peer functionality. If I try to run my NWBrowser in the AppIntent it immediately changes its state to failed with a NoAuth (-65555) error:
nw_browser_cancel [B1517] The browser has already been cancelled, ignoring nw_browser_cancel().
nw_browser_fail_on_dns_error_locked [B1518] DNSServiceBrowse failed: NoAuth(-65555)
NWClientManager: Browser failed: -65555: NoAuth
I haven't found documentation/information on whether NWBrowser should work in an AppIntent extension or not.
In order to make referencing keys for localized strings a little more reliable, our application references generated constants for localized string keys:
This eliminates the potential for developers to misspell a key when referencing a localized strings. And because these constants are automatically generated by the exact same process that provides localized strings for the application, each and every constant is guaranteed to have a localized string associated with it.
I’m currently attempting to implement something similar for the localized strings referenced by our new App Intents. Our initial release of App Intent functionality is simply using string literals to reference localized strings:
However, I am running into several issues when trying to reference the string keys as a constant. The closest I managed to get was defining the constant as either a LocalizationValue or as a StaticString and referencing the constant while initializing the LocalizedStringResource. With this approach, I see no errors from Xcode until I try and compile. What’s more is that the wording of the error being thrown is quite peculiar:
As you can see with the sample code above, I am clearly calling LocalizedStringResource’s initializer directly as Indicated by the error.
Is what I’m trying to do even possible with App Intents? From my research, it does look like iOS app localization is moving more towards using string literals for localized strings. Like with String Catalog’s ability to automatically generate entries from strings referenced in UI without the need for a key. However, we’d prefer to use constants if possible for the reasons listed above.
I have seen some application having custom images in shortcuts app, but after refreing all the apple documentation and source code im yet to figure out a way to show images. the AppShortcutProvider only supports Sfsymbols as of now. then how come other applications is able to do this ? please advice ?
Topic:
App & System Services
SubTopic:
Automation & Scripting
Tags:
Spotlight
Shortcuts
Intents
App Intents
In iOS 18 (beta 1-4) when you set openAppWhenRun = false in your AppIntent of your live activity the perform function never gets called.
In iOS 16 and 17 my live activities work. I have downloaded other apps and in their live activities any button tab which doesn´t open the app is also doing nothing in iOS 18.
Has anyone got this working? Any comments from an Apple engineer on this?
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.
We are looking at the possibility of launching our app through Siri with a locked device. We have the device responding to our App Intent but it is asking to be unlocked first. If the device is locked the intent works perfectly. It just doesn't seem to respect the set intentAuthenticationPolicy.
Thank you for you time looking into this.
We have set these var to .alwaysAllowed and open to true.
static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed
static var openAppWhenRun: Bool = true
Here is our full test code:
import AppIntents
import SwiftUI
// MARK: - App Intents
struct OpenAppIntent: AppIntent {
static var title: LocalizedStringResource = "Open Main App"
static var description: IntentDescription? = .init(stringLiteral: "Opens the App")
static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult {
print("App opened")
return .result()
}
}
struct TestAppShortcutProvider: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OpenAppIntent(),
phrases: [
"Begin \(.applicationName)"
],
shortTitle: "Open App",
systemImageName: "popcorn.fill"
)
}
}
I'm adding widget interactivity to my home screen widgets via buttons and AppIntents, but running into some interesting behavior the way the timeline is reloaded after.
I'm following this guide from Apple
https://developer.apple.com/documentation/widgetkit/adding-interactivity-to-widgets-and-live-activities
And the widget is guaranteed to be reloaded when a button pressed with an intent, But whenever the AppIntent is done with the perform action, the widget timeline is always reloaded twice. It's also interesting to note that both reloads happen after the perform method. If you add a 10 second sleep in the perform, nothing happens for 10 seconds, then both reloads happen.
This issue with this is 2-fold.
calculating and rendering the entire widget timeline can be Networking and DB intensive operations, so I would ideally like to avoid doing all the work twice and save the users battery and processing.
The even worse issue, sometimes data on the server changes in between the split second duplicate widget timeline reloads, causing the widget to flash one state, then update to another a second later which is not a good user experience.
I have a sample project which shows the issue and is very easy to reproduce.
The widget simply keeps track of the number of reloads.
To reproduce:
Add the widget to the homescreen
Press the refresh button, and observe the timeline refresh count always goes up by 2.
I've filed a Feedback and attached the sample project and screen recording for anyone to reproduce.
FB15595835
I need to elicit the location of the user in the Siri intents and so I call:
override init(){ super.init() self.locationManager=CLLocationManager() self.locationManager.delegate = self; self.locationManager.startUpdatingLocation() self.locationManager.requestWhenInUseAuthorization() }
Still neither
public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager)
nor
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
are ever called, notwithstanding the presence of the correct entry in the info.plist, the inclusion of the library and the indication of the delegation with:
class IntentHandler: INExtension, INSendMessageIntentHandling, CLLocationManagerDelegate, UISceneDelegate
are ever called.
Is there any problem with CLLocation manager on intents? What would be a big problem as there is no way to share information with the main app!