App Intents

RSS for tag

Extend your app’s custom functionality to support system-level services, like Siri and the Shortcuts app.

Posts under App Intents tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

URLRepresentableEntity with custom properties
I am trying to implement URLRepresentableEntity on my AppEntity I am following along with the WWDC video here All compiles fine when I use the ID as in the video: extension SceneEntity: URLRepresentableEntity { static var urlRepresentation: URLRepresentation { "https://example.com/scene/\(.id)" } } but my URLs need to use a different property on the Entity. The WWDC video clearly states: "Notice that I'm using the entity’s identifier as an interpolated value. You can use an entity’s ID or any of its properties with the @Property attribute as interpolations in the URL string." So I annotated my entity with the @Property attribute and expected that to work but it doesn't compile. struct SceneEntity: AppEntity { let id: UUID @Property(title: "Slug") var slug: String } extension SceneEntity: URLRepresentableEntity { static var urlRepresentation: URLRepresentation { "https://example.com/scene/\(.slug)" } } Type 'EntityURLRepresentation.StringInterpolation.Token' has no member 'slug' How can I use this API with a property that is not the ID?
0
0
332
Sep ’24
AppShortcutsProvider limitedAvailability in result builder crash
My team is preparing for iOS 18, and wanted to add intents using assistant schemas that are iOS 18 and above restricted. We noticed that the result builder for AppShortcuts added support for limitedAvailabilityCondition from iOS 17.4 so we marked the whole struct as available from it. The app compiles but writing a check like below inside appShortcuts property a crash will happen in iOS 17.5 runtime. (Removing the #available) is solving this problem. if #available(iOS 18, *) { AppShortcut( intent: SearchDonut(), phrases: [ "Search for a donut in \(.applicationName)" ], shortTitle: "search", systemImageName: "magnifyingglass" ) } We tried out putting the os check above and returning shortcuts in arrays and that both compiles and runs but then AppShortcuts.strings sends warnings that the phrases are not used (This phrase is not used in any App Shortcut or as a Negative Phrase.) because the script that extracts the phrases somehow fails to perform when shortcuts are written like below: static var appShortcuts: [AppShortcut] { if #available(iOS 18.0, *) { return [ AppShortcut( intent: CreateDonutIntent(), phrases: [ "Create Donut in \(.applicationName)", ], shortTitle: "Create Donut", systemImageName: "pencil" ) ] } else { return [ AppShortcut( intent: CreateDonutIntent(), phrases: [ "Create Donut in \(.applicationName)", ], shortTitle: "Create Donut", systemImageName: "pencil" ) ] } } This is very problematic because we can't test out on TF with external users new intents dedicated for iOS 18. We filed a radar under FB15010828
0
2
215
Sep ’24
App with @AssistantIntent immediately crashes on iOS 18.1 Beta 3
When building and running an app on iOS 18.1 Beta 3 a fresh sample app with an @AssistantIntent will immediately crash. Using a sample Assistant Intent from the developer documentation site will cause this. Removing the @AssistantIntent macro will allow the app to run. Using Xcode 16.1 beta. dyld[1278]: Symbol not found: _$s10AppIntents15AssistantSchemaV06IntentD0VAC0E0AAWP Referenced from: <DC018008-EC0E-3251-AAFC-5DEB51863F17> /private/var/containers/Bundle/Application/2726C2CE-0255-4692-A7CA-B343146D4A83/Runner.app/Runner.debug.dylib Expected in: <E9AF073B-B6E0-31B8-88AA-092774CEEE3D> /System/Library/Frameworks/AppIntents.framework/AppIntents (FB14949135)
1
1
471
Aug ’24
Sirikit "Create" category show create button but siri don't accept "create" command
I develop a siri function with my App. In the custom intent, I choose "Create" category. And when I run this command, create button would be displayed. But the strange thing, when I say "create", no response. I say "yes", "okay", "sure", all of them worked. Only "create", didn't work. If we show a create button, the "create" command also need work. Can anyone help me, I want "create" command also worked.
1
0
295
Sep ’24
OpenURLIntent to custom url scheme
Has anyone figured out how to use the new OpenURLIntent intent to open their own app using a custom URL scheme? I have the following code: @available(iOS 18, *) struct BarcodeScannerControlWidget: ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: "scannerIntent") { ControlWidgetButton(action: OpenBarcodeScannerIntent()) { Label("Scan Barcode", systemImage: "barcode.viewfinder") } } .displayName("Scan Barcode") } } @available(iOS 18, *) struct OpenBarcodeScannerIntent: AppIntent { static var title: LocalizedStringResource = "Scan Barcode" func perform() async throws -> some IntentResult & OpensIntent { let url = "myscheme:///barcodeScanner let openURLIntent = OpenURLIntent(url) return .result(opensIntent: openURLIntent) } } Running this intent doesn't seem to do anything. If I replace the URL with say "https://www.apple.com", the intent opens up safari with that URL.
4
3
892
Sep ’24
iOS18 Control Widget that opens parent app
I feel like this is probably really easy and hopefully I'm just doing something stupid, but I can't get a control to open the app it belongs to. Taking the intent itself directly from the example code, and it does nothing when the button is pressed. struct OpenAppWidget: ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration( kind: "com.dfjkldfsfrw.ControlCenterWidgetDemo.OpenApp" ) { /// This one - based on the demo code - doesn't work on simulator or device ControlWidgetButton(action: LaunchAppIntent()) { Label("Launch App", systemImage: "arrow.up.right") } } .displayName("Launch App") .description("A an example control that launches the parent app.") } } struct LaunchAppIntent: OpenIntent { static var title: LocalizedStringResource = "Launch App" @Parameter(title: "Target") var target: LaunchAppEnum } enum LaunchAppEnum: String, AppEnum { case timer case history static var typeDisplayRepresentation = TypeDisplayRepresentation("Productivity Timer's app screens") static var caseDisplayRepresentations = [ LaunchAppEnum.timer : DisplayRepresentation("Timer"), LaunchAppEnum.history : DisplayRepresentation("History") ] } I've tried adding a perform( function to the intent, and setting openAppWhenRun to true, but they don't seem to make a difference. I've also tried using an OpenURLIntent in the result of the button's intent to open the app based on a custom url scheme, but whilst that seems to work in the simulator, it doesn't work on a real device. What am I missing?
3
2
888
Aug ’24
How can I share code between app and widget that contains uiapplication?
OK, so I'm trying to share some utils classes for logging. The problem is a use-case where I want to create a debug notification. However, inside the app, I want to show a popup instead if the app is showing, but I can't share that code because it uses UIApplication.shared.ApplicationState. I've tried gating it off with all sorts of methods, @available etc. but I get compilation error "unavailable for application extensions" Example of me trying: static func doNotification(_ header: String, message: String) { //so I'm trying to gate off the code that only can be called in an extension , and in addition I have @available below if(isAppExtension()){ doNotificationFromExtension(header, message: message) }else{ doNotificationFromApp(header, message: message) } } @available(iOSApplicationExtension, unavailable) static func doNotificationFromApp(_ header: String, message: String) { let state = UIApplication.shared.applicationState if state != .active { //my dialog handler in-app popup }else{ NotifUtils.createLocalNotification(message, header: header, category: NOTIFICATION_CATEGORY_DEBUG, playSound: false) } } //here I know that I'm in an extension, so app isn't showing - always local notification static func doNotificationFromExtension(_ header: String, message: String) { NotifUtils.createLocalNotification(message, header: header, category: NOTIFICATION_CATEGORY_DEBUG, playSound: false) } static func isAppExtension() -> Bool { return Bundle.main.executablePath?.contains(".appex/") ?? false } Is there any way to share the code like this? The reason I want to do this is because I have various live activity code that I'd want to re-use, but this is a show.-stopper.
3
0
415
Aug ’24
Would like feedback on handling multiple button presses while live activity intent Is processing
I am working on a live activity with a button that will do a network call when pressed on. I want to make sure that it can only be pressed once, and then ignored while the request is processed. This is what I did: Since it seems that a new intent object is created for each button press, I am using a static synchroniser like this: private var _isBusy: Bool = false private var _timestamp: Date? = nil private let queue: DispatchQueue private let resetInterval: TimeInterval init(resetInterval: TimeInterval = 60, queueLabel: String = "default.synchronizedBoolQueue") { self.resetInterval = resetInterval self.queue = DispatchQueue(label: queueLabel) } var isBusy: Bool { get { return queue.sync { return _isBusy } } set { queue.sync { _isBusy = newValue } } } func setIfNotBusy() -> Bool { return queue.sync { let now = Date() if let timestamp = _timestamp { if now.timeIntervalSince(timestamp) > resetInterval { // Reset if it was more than the specified interval ago _isBusy = false _timestamp = nil } } if !_isBusy { _isBusy = true _timestamp = now return true } return false } } func clearBusy() { queue.sync { _isBusy = false _timestamp = nil } } } Then, in my intent I have: private static let synchronizedBoolean = SynchronizedBoolean(queueLabel: "myIntent") ... func perform() async throws -> some IntentResult { NSLog("---LIVE perform() called") if(!UserEventIntent.synchronizedBoolean.setIfNotBusy()){ NSLog("---LIVE Was already in progress!") }else{ //doing intent logic here UserEventIntent.synchronizedBoolean.clearBusy() } } I am pretty new to Swift, so my hope is that someone more experienced than me could tell me if this a reasonable approach or if I'm missing anything? A big question - let's say I go into the perform() method, and while I'm in there, the user presses the button and the intent is called again. I get the "already in progress", but the method must still provide a result. Will that effect the intent already in progress? Thoughts much appreciated.
2
0
297
Aug ’24
AppIntents Parameter requestValue not working in iOS 18 when parameter is not in parameterSummary
In iOS 18, the requestValue method no longer works when the parameter it is called on is not included in the parameterSummary of an AppIntent. This issue causes the app to fail to present a prompt for the user to select a value, resulting in an error with the message: Domain=NSCocoaErrorDomain Code=4099 "The connection from pid 40685 on anonymousListener or serviceListener was interrupted, but the message was sent over an additional proxy and therefore this proxy has become invalid." Steps to Reproduce: Create a simple AppIntent with the following code: import AppIntents struct Intent: AppIntent { static let title: LocalizedStringResource = "Intent" static var parameterSummary: some ParameterSummary { Summary("Test \(\.$category)") {} } @Parameter(title: "Category") private var category: CategoryEntity? @Parameter(title: "Hidden Category") private var hidden: CategoryEntity? @MainActor func perform() async throws -> some ReturnsValue<CategoryEntity?> { var result: CategoryEntity? do { result = try await $hidden.requestValue("Select category") // Doesn't work since iOS 18 as $hidden is not set in parameterSummary } catch { print("\(error)") } return .result(value: result) } } Run the code on a device with iOS 18. Observe that the requestValue method fails to present the selection prompt and instead throws an error. Expected Results: The app should successfully present a prompt for the user to select a value for the hidden parameter using requestValue, even if the parameter is not included in the parameterSummary. Actual Results: The app fails to present the selection prompt and throws an error, making it impossible to use requestValue for parameters not included in parameterSummary. Version/Build: iOS 18.0 Configuration: Tested on various devices running iOS 18. Is there a change in the API that I might have missed?
4
2
518
Sep ’24
Unable to get widgetConfigurationIntent from NSUserActivity
I have a simple lock screen widget that when tapped, should open a certain flow in my app. This works fine when the main app is already running, but when tapped while the app is not running, the app launches, but it doesn't open the flow I want it to. When I debug it (see flow below), it seems that the problem come from the widgetConfigurationIntent(of:) function on NSUserActivity. When the app is cold launched, I get the expected NSUserActitivity, but the function above returns nil. That same piece of code returns a valid WidgetConfigurationIntent if the app is already running. Any ideas what might go wrong? There's nothing in the documentation hinting about why this might happen, so I feel a bit lost. BTW, this is how a debug opening from scratch with a lock screen widget: Select "Wait for the executable to be launched" in the scheme editor in Xcode. Make sure the app is not running on device or simulator Start debugging session in Xcode (app is built but not opened) Lock device, tap already installed lock screen widget. App launches and my breakpoint is hit.
0
0
206
Aug ’24
iOS18 Control Widget dynamic switch intent
Objective: When the app is running, directly operate the app without launching it. When the app is not started, wake up the app to perform the corresponding operation. Premise: AppIntent's openAppWhenRun can dynamically control whether the app is launched, but the variable itself cannot be changed. Therefore, the idea is to refresh the widget when the app is started or terminated, displaying different content (binding different intents) to achieve the goal. However, there are persistent issues during code implementation. struct ControlWidgetContent: ControlWidgetTemplate { var body: some ControlWidgetTemplate { if (applaunched) { return ControlWidgetButton(action: Aintent()) { Label("xxxx", systemImage: "calendar") } } else { return ControlWidgetButton(action: Bintent()) { Label("xxxx", systemImage: "calendar") } } } } @available(iOS 18.0, *) struct ControlWidgetContent: ControlWidget { let kind: String = "ControlWidgetInterface" var body: some ControlWidgetConfiguration { StaticControlConfiguration( kind: kind ) { ControlWidgetContent() }.displayName("xxxx") } } it preports error: Function declares an opaque return type 'some ControlWidgetTemplate', but the return statements in its body do not have matching underlying types Return statement has underlying type 'ControlWidgetButton<Label<Text, Image>, ControlWidgetButtonDefaultActionLabel, PlayDayRcmdIntent>'
2
0
497
Aug ’24
What is the correct way to modify a SceneStorage variable from an AppIntent to one scene only for iPad SplitView mode
Apple's sample code 'Trails' supports multiple scenes, however everything is using shared state across the scenes. Put the app in Split View mode and have two windows of the app running and navigate, you can see both mirror each other. Works as designed, it is using a shared 'navigation model' across all scenes. https://developer.apple.com/documentation/appintents/acceleratingappinteractionswithappintents I would like to know if there is a supported or recommended way to modify individual scene storage from within the perform body of an AppIntent. The objective is to have App Shortcuts that launch different tabs in a TabView or different selections in a List. In short, I want to deep link to features, but account for more than one scene being open on iPad and only have programatic navigation happen on the scene that is 'foremost' or the 'activated' one in Split View. I have it working with either a @Dependency or posting a Notification with my main ContentView listening to the other end, but it changes all scenes.
0
0
440
Aug ’24
AppIntent @Dependency Throwing Error
I'm not really sure if I'm using the right lingo here because there's so little documentation on this, so apologies in advance. I have an app with a few custom intents that I'm attempting to transition to AppIntents. I have the newly transitioned intents showing up in the Shortcuts app as expected, however when I run them I get an immediate failure saying "The operation couldn't be completed" (see photo). Note that the "AppIntentsClient" class mentioned in the photo is the dependency I'm trying to import. I've narrowed it down to the @Dependency that I'm using in my intent handler. At the top of the intent handler I have a line: @Dependency private var appIntentsClient: any AppIntentsClient // NOTE: AppIntentsClient is a protocol -- could that be the issue? And if I comment out this line, the intent no longer throws that error. I'm following the guidelines shown in sample apps by setting the dependency on my main app's startup in didFinishLaunchingWithOptions like so: // gets called by the main app `didFinishLaunchingWithOptions` func onDidFinishLaunching() { let adapter = AppIntentsAdapter() //AppIntentsAdapter adheres to protocol AppIntentsClient self.appIntentsAdapter = adapter AppDependencyManager.shared.add(dependency: adapter) MyAppShortcuts.updateAppShortcutParameters() } Unfortunately there is virtually no documentation around AppDependencyManager or AppDependencies in general. Both documentation pages have at most one line, but don't indicate why this would be failing for me. Is there any information out there on why these errors may be happening? I've also looked at the Console app to see if the OS logs anything, but nothing of value was found. https://developer.apple.com/documentation/appintents/appdependencymanager https://developer.apple.com/documentation/appintents/appdependency
2
1
558
Aug ’24
Manually call App Intent from main app target
I would like to call my App Intent directly from my main app target, in an effort to start a live activity in the background when I receive a silent push notification from the server. I have seen in one of the WWDC developer lounges on Slack that this should be possible. Here is how I tried doing it: (it was recommended like that in the lounge) let appIntent = LiveActivityRefreshIntent() Task { try await appIntent() } But I get a compiler error: Instance method 'callAsFunction(donate:)' requires the types '(some IntentResult).Value' and 'Never' be equivalent It's strange because as far as I can tell, I cannot declare my perform method as returning Never. Here is the signature and return value of my App Intent's perform method: func perform() async throws -> some IntentResult { LiveActivityController.shared.updateLiveActivities() return .result() } Is there still a way to call the app intent from my code? If so, how?
0
1
342
Aug ’24
Using OpenIntents with voice
Hi, I am working with AppIntents, and have created an OpenIntent with a target using a MyAppContact AppEntity that I have created. This works fine when running from Shortcuts because it pops up a list of options from the 'suggestedEntities` method. But It doesn't work well when using with Siri. It invokes the AppIntent, but keeps repeatedly asking for the value of the 'target' entity, which you can't really pass in with voice. What's the workaround here? Can an OpenIntent be activated by voice as well?
0
0
547
Aug ’24
iOS18 AudioPlaybackIntent respond too slow when app not launched
here's my case, i develop a control widget, user can push a controlwidget to play music without open the app. i bind a AudioPlaybackIntent to the widget. when user click the widget, the app will receive the intent and start to play music. it works perfect when app running in background or foreground. but when app not launched, the respond is too slow, it takes several seconds to start play music. is there any way to make the respond faster when app not launched? if i want to do something when app not launched, what should i do?
2
0
576
Aug ’24
ControlWidgetToggle can't be refresh when it action with a LiveActivityIntent.
Hi, I'm trying to implement the iOS18 ControlWidget features. When i turn on a ControlWidgetToggle that action with a LiveActivityIntent, the toggle will turn off automatic. The toggle state is read from my sharemanger, but it state won't refresh even i use the ControlCenter.shared.reloadAllControls(). Here is my code. struct TimerLiveActivityControl: ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: Self.kind) { ControlWidgetToggle(isOn: ShareManager.shared.isLiveActivityTimerOn, action: LiveActivityTimerIntent()) { isTurnedOn in Image(systemName: isTurnedOn ? "fan.fill":"fan") Text(isTurnedOn ? "Turned off" : "Turned On") } label: { Text("Live Activity Timer") } } } } struct LiveActivityTimerIntent: LiveActivityIntent, SetValueIntent { static var title: LocalizedStringResource { "Live Activity timer" } @Parameter(title: "is Turned On") var value: Bool @MainActor func perform() async throws -> some IntentResult { TimerLiveActivityTimer.shared.duration = 10 TimerLiveActivityTimer.shared.startTimer() return .result() } } func startTimer() { self.startActivity() self.isLiveActivityTimerOn = true Timer.scheduledTimer(withTimeInterval: TimeInterval(self.duration), repeats: false) { timer in self.isLiveActivityTimerOn = false ControlCenter.shared.reloadAllControls() self.endActivity() } //The ControlWidgetToggle can't refresh even i refresh it all time Timer.scheduledTimer(withTimeInterval: TimeInterval(0.1), repeats: true) { timer in ControlCenter.shared.reloadAllControls() } } However the code can work if I use a single SetValueIntent. My Xcode version is 16.0 beta, use iOS 18.0 simulator.
1
0
474
Aug ’24
SetFocusFilterIntent `perform()` method is not called on iOS 18 beta
I’ve set up a focus filter, but the perform() method in SetFocusFilterIntent isn't called when the focus mode is toggled on or off on my iPhone since I updated to iOS 18 beta (22A5326f). I can reproduce the issue for my app, but focus filters are also broken for any third-party apps installed on my phone, so I guess it's not specific to how I've implemented my filter intent. This used to work perfectly on iOS 17. I didn't change a single line of code, and it broke completely on the latest iOS 18 beta. I've filed a bug report including a sysdiagnose (FB14715113). To the developers out there, is this something you are also observing in your apps?
0
0
345
Aug ’24