Post not yet marked as solved
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!
Post not yet marked as solved
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?
Post not yet marked as solved
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?
Post not yet marked as solved
We have an Intent configurable widgets in our app that allows user to choose theme for widget.
After adopting App Intent for widget configuration, existing widget does not preserve the selected theme and it resets the value.
Post not yet marked as solved
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
Post not yet marked as solved
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?
Post not yet marked as solved
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!
Post not yet marked as solved
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?
Post not yet marked as solved
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()
}
}
Post not yet marked as solved
Hi everyone!
Even though our project has no intent definitions or anything related to App Intents or Siri intents, the Xcode 15 is stuck on the "Extract app intents metadata" phase when building one of our internal frameworks.
Is there anything we can do to fix that?
Post not yet marked as solved
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 !
Post not yet marked as solved
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?
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?
Post not yet marked as solved
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
Post not yet marked as solved
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)
'''
Post not yet marked as solved
I want to run a third party shortcut after an an app intent without opening the shortcuts app. I tried using the deep linking URL method but it opens the shortcut app to run the shortcu.
Post not yet marked as solved
Building iOS app using Xcode 15 Beta 3 - clean build
Step: "Validate app shortcut strings metadata"
Error: "Unable to call validation: The data couldn’t be read because it isn’t in the correct format"
FB12536037
Post not yet marked as solved
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:
`
Post not yet marked as solved
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?
Post not yet marked as solved
I have run the demo "Food Truck", which implement the AppShortcut. I found that the shortcuts need to be added to shortcut and can't to be search in the spotlight even I had make sure it is "suggest in search"
iOS 17.0 simulator