App Intents

RSS for tag

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

App Intents Documentation

Posts under App Intents tag

163 Posts
Sort by:
Post not yet marked as solved
1 Replies
679 Views
I'm trying to put together an app intent that allows a user to navigate to a specific part of my app. I've built a basic intent, and set up an AppEnum with a case for each "screen" in my app a user should be allowed to navigate to (e.g. "All Posts", "Favourite Posts", etc.). In addition, I'd like to include additional parameters based on the enum selected. For example, I'd like to include an enum case "Post" where a user can configure a specific post to navigate to. This would mean I can have an enum of "All Posts", "Specific Post", "Favourite Posts" etc. which is cleaner than having a separate intent for "Open Specific Post"... Is this possible? I can see ParameterSummaryBuilder, AppIntent.Switch etc. but there are no docs or examples using these. Can you provide more information on whether this is possible, and show an example of Swift code to do this. Thanks!
Posted
by
Post not yet marked as solved
0 Replies
728 Views
We have an AppIntent that starts streaming data in its perform() function with a URLSession. This may be a quick operation, or it may take some time (more than 30 seconds but less than a minute). Is there any way we can keep that streaming data URLSession active when the AppIntent asks the user to continue with requestConfirmation? What we have seen so far is that any operation the AppIntent takes in its perform() function that interacts with the user causes the URLSession to be abruptly terminated with a NSURLErrorNetworkConnectionLost error when the app is not in the foreground. If the app is currently running in the foreground then the session does remain active and data continues to stream in. Sadly, our primary use case is for the Siri/Shortcuts interaction to happen with openAppWhenRun set to false and not require the user to open the app. In that case (with the AppIntent invoked while the app is in the background) the network connection is dropped. It has been frustrating in initial development because on the simulator the connection is not dropped and data continues to stream in, even while the app is in the background. On a physical device, this is not the case. The only condition we have found to have the network connection maintained is with the app in the foreground when the AppIntent is run. Here is what we have now: struct AskAI: AppIntent { static var title: LocalizedStringResource = "Ask" static var description: IntentDescription = IntentDescription("This will ask the A.I. app") static var openAppWhenRun = false @Parameter(title: "Prompt", description: "The prompt to send", requestValueDialog: IntentDialog("What would you like to ask?")) var prompt: String @MainActor func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView & ReturnsValue<String> { var continuationCalled = false //Start the streaming data URLSession task Task<String, Never> { await withCheckedContinuation { continuation in Brain.shared.requestIntentStream(prompt: prompt, model: Brain.shared.appSettings.textModel, timeoutInterval: TimeInterval(Brain.shared.appSettings.requestTimeout )) { result in if !continuationCalled { continuationCalled = true continuation.resume(returning: Brain.stripMarkdown(result)) } } } } //Start the intentTimeout timer and early out if continuationCalled changed let startTime = Date() let timeout = Brain.shared.appSettings.intentTimeout while !continuationCalled && Date().timeIntervalSince(startTime) < timeout { try? await Task.sleep(nanoseconds: 1_000_000_000) } //At this point either the intentTimeout was reached (data still streaming) or continuationCalled is true (data stream complete) //best effort for Siri to read the first part and continue as more is received var allReadResponse = "" var partialResponse = "" while !continuationCalled { partialResponse = Brain.shared.responseText.replacingOccurrences(of: allReadResponse, with: "") allReadResponse += partialResponse do { let dialogResponse = partialResponse + " --- There is more, would you like to continue?" //THIS WILL TERMINATE THE URLSession if the app is not in the foreground! try await requestConfirmation(result: .result(dialog: "\(dialogResponse)") { AISnippetView() }) } catch { return .result( value: Brain.shared.responseText, dialog: "", //user cancelled, return what we have so far but we've already spoken the dialog view: AISnippetView() ) } } //Read the last part (or the whole thing it it was retrieved within the intentTimeout) let remainingResponse = Brain.shared.responseText.replacingOccurrences(of: allReadResponse, with: "") return .result( value: Brain.shared.responseText, dialog: "\(remainingResponse)", view: AISnippetView() ) } } With this logic, Siri will read the first part of the response data when the timer expires and continuationCalled is false. The data is still streaming and will continue to come in while she is speaking - ONLY IF THE APP IS IN THE FOREGROUND. Otherwise the call to requestConfirmation will terminate the connection. Is there any way to get the task with the requestIntentStream URLSession to stay active?
Posted
by
Post not yet marked as solved
0 Replies
376 Views
Is it possible to use integer parameter in parameterized phrase? I have an app shortcut where user needs to provide an integer for the app to process it. But the phrase is not recognised by Siri. The one without integer parameter works fine. struct LogWaterShortcuts: AppShortcutsProvider { @AppShortcutsBuilder static var appShortcuts: [AppShortcut] { AppShortcut( intent: LogWaterIntent(), phrases: [ "Log Water in \(.applicationName)", "Log \(\.$quantity) Water in \(.applicationName)" ], shortTitle: "Log Water", systemImageName: "plus" ) } } Is it not possible or I am doing something wrong? If it is not possible then is there any alternative that I can use to achieve the same?
Posted
by
Post not yet marked as solved
2 Replies
847 Views
I want to add shortcut and Siri support using the new AppIntents framework. Running my intent using shortcuts or from spotlight works fine, as the touch based UI for the disambiguation is shown. However, when I ask Siri to perform this action, she gets into a loop of asking me the question to set the parameter. My AppIntent is implemented as following: struct StartSessionIntent: AppIntent { static var title: LocalizedStringResource = "start_recording" @Parameter(title: "activity", requestValueDialog: IntentDialog("which_activity")) var activity: ActivityEntity @MainActor func perform() async throws -> some IntentResult & ProvidesDialog { let activityToSelect: ActivityEntity = self.activity guard let selectedActivity = Activity[activityToSelect.name] else { return .result(dialog: "activity_not_found") } ... return .result(dialog: "recording_started \(selectedActivity.name.localized())") } } The ActivityEntity is implemented like this: struct ActivityEntity: AppEntity { static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "activity") typealias DefaultQuery = MobilityActivityQuery static var defaultQuery: MobilityActivityQuery = MobilityActivityQuery() var id: String var name: String var icon: String var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(self.name.localized())", image: .init(systemName: self.icon)) } } struct MobilityActivityQuery: EntityQuery { func entities(for identifiers: [String]) async throws -> [ActivityEntity] { Activity.all()?.compactMap({ activity in identifiers.contains(where: { $0 == activity.name }) ? ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) : nil }) ?? [] } func suggestedEntities() async throws -> [ActivityEntity] { Activity.all()?.compactMap({ activity in ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) }) ?? [] } } Has anyone an idea what might be causing this and how I can fix this behavior? Thanks in advance
Posted
by
Post not yet marked as solved
3 Replies
833 Views
We have an app that uses Siri Shortcuts in iOS 16. WWDC '23 announced more flexible shortcut phrase matching in iOS 17 when apps are built with Xcode 15 run on Sonoma. I've downloaded and installed (Xcode and Sonoma) and rebuilt the app. I've ensured that "APP_SHORTCUTS_ENABLE_FLEXIBLE_MATCHING = YES" in the Build Settings. Unfortunately the App Shortcuts Preview Window shows the following error when I click on my build "No Flexible Matching Assets - This target is for a platform which is not supported by Flexible Matching or does not have Flexible Matching enabled" Other things I tried: I set our minimum deployment target to iOS 17 and built for an iOS 17 Simulator. Any ideas on how to get flexible matching for shortcut phrases?
Posted
by
Post not yet marked as solved
5 Replies
1.8k Views
I have AppIntent code which lives in my app package that can not easily be decoupled and migrated into its own standalone framework or extension. This is because this intent has some action that relies on my app's network and core data stack. I'd like to expose this existing intent in some way to a Button in a widget, but so far I have not had success. Is this currently possible with AppIntentPackage or some other means? Is there a way I can use AppIntents to pass a message back to the app? How should I approach this? Thank you!
Posted
by
Post not yet marked as solved
3 Replies
853 Views
I have a home widget with buttons (new in iOS 17). In order to prevent taking action if the user taps on the widget buttons accidentally, I want to ask the user for confirmation. It appeared that requestConfirmation be exactly what I needed, but no confirmation view shows up when I invoke this method in the perform function. I have tried the following: try await requestConfirmation(result: .result(dialog: "Are you sure you want to do this?") { Image(.mdlsWhite) }) and this alternative: let confirmed: Bool = try await $name.requestConfirmation(for: self.name, dialog: IntentDialog(stringLiteral: msg)) Neither option work. I am starting to think that the requestConfirmation is not to be used with Home Widgets. Is there a better way to handle confirmations for buttons included in a Home Widget?
Posted
by
Post not yet marked as solved
2 Replies
1k Views
I'm trying to localize an iOS App Intent, but my strings are in a different table/file ("AppIntents.strings"). For this reason I'd like to create a wrapper that automatically sets this table. However, this only seems to work when I directly set the LocalizedStringResource. If I create a method that returns it, it does not work. Using a static property also does not seem to work. In these two cases, it seems to fall back to the class name of my intent ("ExampleIntent"). Below is an example of what I've tried. Is there a way to make this work? @available(iOS 16, *) extension LocalizedStringResource { static func demo(_ key: String.LocalizationValue) -> LocalizedStringResource { LocalizedStringResource(key, table: "AppIntents") } static var demo2: LocalizedStringResource { LocalizedStringResource("localization.key", table: "AppIntents") } } @available(iOS 16, *) struct ExampleIntent: AppIntent { // This works static var title: LocalizedStringResource = LocalizedStringResource("localization.key", table: "AppIntents") // This does not work // static var title: LocalizedStringResource = .demo("localization.key") // This does not work either // static var title: LocalizedStringResource = .demo2 func perform() async throws -> some IntentResult { return .result() } }
Posted
by
Post not yet marked as solved
11 Replies
2.3k Views
Hi, I am trying to integrate the new AppIntentsPackage protocol into my application. Especially what I want to do is to create a dedicate SPM package which holds all my app intents and then share that with my widget extension for Widget intents as well as the main iOS app for powering an AppShortcutProvider. Unfortunately I run into an issue here. I have the following explanatory setup: SPM package called ProjectAppIntents iOS target My AppIntents SPM package //Package: ProjectAppIntents public struct TestAppIntent: AppIntent { public static var title: LocalizedStringResource = "TestAppIntent" @Parameter(title: "Parameter1", optionsProvider: ParameterOptionProvider()) public var parameter: String public init(parameter: String) { self.parameter = parameter } public init() { } public func perform() async throws -> some IntentResult & ReturnsValue { .result(value: 5) } } struct ParameterOptionProvider: DynamicOptionsProvider { func results() async throws -> [String] { return ["Hello", "World"] } } public struct ProjectAppIntentsPackage: AppIntentsPackage { } My iOS app // Target: iOS import ProjectAppIntents struct ProjectApp: App { var body: some Scene { WindowGroup { ContentView() } } } extension ProjectApp: AppIntentsPackage { static var includedPackages: [AppIntentsPackage.Type] = [ ProjectAppIntentsPackage.self ] } struct ProjectShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: TestAppIntent(), phrases: ["Start a \(.applicationName)"], shortTitle: "Hello World", systemImageName: "house" ) } } When I now try to compile my app, I get the following build error: 2023-06-25 09:53:47.853 appintentsnltrainingprocessor[44848:2059163] Parsing options for appintentsnltrainingprocessor 2023-06-25 09:53:47.854 appintentsnltrainingprocessor[44848:2059163] Starting AppIntents SSU YAML Generation 2023-06-25 09:53:47.868 appintentsnltrainingprocessor[44848:2059163] error: The action TestAppIntent referenced in App Shortcut does not exist Command AppIntentsSSUTraining failed with a nonzero exit code So for me it seems like the compiler cannot find the AppIntent defined in an SPM package. Am I doing something wrong here or does the AppIntentsPackage protocol not work with SPM packages ? Thanks a lot for helping !
Posted
by
Post not yet marked as solved
0 Replies
918 Views
Hello! I'm trying to donate an Intent to iOS using IntentDonationManager, following the methods described in the documentaion. try await IntentDonationManager.shared.donate(intent: MyIntent()) // succeeded However, I'm not seeing any effect of this action anywhere in the system (iOS 17 and 16). I have debugged it on both the simulator and a physical device, and I have also enabled the "Display Recent Shortcuts" toggle in the developer settings, but I still don't see any relevant suggestions appearing. Similarly, the issue also occurs with the old SiriKit framework, where INInteraction.donate(completion:) doesn't seem to have any observable effect. I recall that in iOS 15, the simulator would immediately present the donated Shortcut action on the lock screen and Spotlight page. However, starting from iOS 16 and continuing to the current iOS 17 beta 1/2, I haven't been able to achieve the same behavior using the same code. Another similar report: https://developer.apple.com/forums/thread/723109 So is there any way to test or verify the results of this donation action?
Posted
by
Post marked as solved
2 Replies
1.9k Views
I'm working on creating App Shortcuts for my app to show up in the Shortcuts app and Spotlight. One new feature this year is the option to add your apps tint color as a background, but I'm not able to get this to work. I have added the items NSAppIconActionTintColorName (String) and NSAppIconComplementingColorNames (Array?) to my info.plist file that where briefly mentioned in the WWDC23 video, but they don't seem to have any effect. Has anyone got these to work in their project?
Posted
by
Post not yet marked as solved
0 Replies
352 Views
AppShortcut( intent: AIChatIntentStartChat(), phrases: [ AppShortcutPhrase("Call (.applicationName)"), ] ) I follow the Dive into App Intents tutorial in WWDC22,but my shortcut does not automatically show up in the Shortcuts app
Posted
by
Post not yet marked as solved
1 Replies
901 Views
I'm playing around with Interactive Widgets and I am trying to make one that starts playing audio content without bringing the app to the foreground. The new Button used in interactive widgets accepts an AppIntent, but INPlayMediaIntent doesn't conform to AppIntent. Starting to play something directly from an AppIntent doesn't seem to work either. The system kills my process if I try to call the following from an AppIntent: ''' try! AVAudioSession.sharedInstance().setActive(true) '''
Posted
by
Post not yet marked as solved
1 Replies
692 Views
I have implemented a code that answers my question with Siri, but I want to have a continuous conversation like in ChatGPT app. Can't understand documentation properly to do that. import AppIntents @available(iOS 16.0, *) struct MyAppShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: AskQuestionIntent(), phrases: [ "Ask \(.applicationName)", "Ask \(.applicationName) a question" ] ) } } @available(iOS 16, *) struct AskQuestionIntent: AppIntent { static var title: LocalizedStringResource = "Ask question" static var description = IntentDescription("Ask questions directly") @Parameter(title: "Question", requestValueDialog: "What would you like to ask?") var question: String @MainActor func perform() async throws -> some OpensIntent { return .result(opensIntent: self, dialog: IntentDialog(stringLiteral: "some result")) } } Here is How it looks like in ChatGPT: And here is my app: `
Posted
by
Post not yet marked as solved
0 Replies
403 Views
struct MyIntentConfiguration: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Habit Selector" static var description: IntentDescription = IntentDescription("Select Habits") @Parameter(title: "Select Habits", size: 9) var habits: [HabitEntity] } The previous code correctly allows the user to pick the 9 habits they want to track in the widget. But initially the widget is empty. How can I define default values for the Parameter "habits" taking into account that the values are dynamic?
Posted
by