I have implemented a custom AppIntent in a macOS (14+) application and also added AppShortcuts. However whenever I try to launch it from Siri I get "Sorry something went wrong". In the documentation it states that Siri should automagically index and pick up these shortcuts/ intents. What ma I missing ?
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
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
When i use Xcode16 Beta4, I finish some code
for example
@available(iOS 18.0, *)
struct Test001ControlWidget: ControlWidget {
let kind: String = "Test001ControlWidgetKind"
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: kind, content: {
ControlWidgetButton(action: Test001ControlAppIntent(), label: {
HStack {
Image("controlcenter_point")
Text("Test001")
}
})
})
.displayName("Test001")
}
}
@available(iOS 18.0, *)
struct Test001ControlAppIntent: AppIntent {
static let title: LocalizedStringResource = "Open Demo Some Page"
static var isDiscoverable: Bool = false
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult & OpensIntent {
let defaultIntent = OpenURLIntent()
guard let url = URL(string: Test001JumpType.sohuWatchPoint.jumpLink()) else { return .result(opensIntent: defaultIntent) }
return .result(opensIntent: OpenURLIntent(url))
}
}
The icon can be displayed normally and icon type is png.
And deep link also jump normally.(Note: The control widget file target membership are main app and widgetExtension)
But iOS18 RC code is no working and icon show "?"
How do I deal with these issues?
I hope to hear from you soon.
Tks a lot...
Hello everyone,
Xcode 16.0 SwiftData project. CloudKit. WidgetConfigurationIntent.
For some reason, I see a really weird behavior.
I have a shared ModelContainer and an interactive widget where I update the model data through an app intent.
This is my model -
@MainActor
class ItemsContainer {
static let shared = ItemsContainer()
var sharedModelContainer: ModelContainer!
init() {
self.sharedModelContainer = container()
}
func container() -> ModelContainer? {
if let sharedModelContainer {
return sharedModelContainer
}
let schema = Schema([
Session.self,
])
let modelConfiguration: ModelConfiguration
modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .automatic)
do {
let container = try ModelContainer(for: schema, configurations: [modelConfiguration])
self.sharedModelContainer = container
return container
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}
}
And this is how I get the model context across the app and the app intent -
let modelContext = ModelContext(ItemsContainer.shared.sharedModelContainer)
The problem is that somehow, when I update the model context in the app and then in the widget (I save the context after every change), the data is synced between the app and the widget, but then, the data is changed back to the previous state and kind of ignores the widget changes.
Didn't happen before iOS 18/Xcode 16.
Any idea?
Thanks a lot!
Is there a time limit for the perform method execution in iOS? I'm implementing App Intents that call an API from the perform method. Based on my testing, it works fine if the API completes within 10 seconds. However, if it takes longer, Siri ends the process with an error.
I have a Live Activity with a button that updates a SwiftData model. This used to work in iOS 17, but not on iOS 18. The reason is that in iOS 17, when you run an AppIntent from a Live Activity, the perform() method would run in the main app's process, meaning it had access to the app's ModelContainer/ModelContext. However, in iOS 18, this is no longer the case, and the perform() method of an AppIntent now runs in the extension's process.
While I can still construct a new ModelContainer & ModelContext in the AppIntent's perform() method, the main app's container and context will not see these changes until the app is relaunched.
How can I make this work in iOS 18 now that an AppIntent executed from an extension runs in a different process from the main app?
Dear community, 3 Questions
1 On which processor are shortcuts being executed (the script flow) when started from Apple Watch?
2 Same question for the single intents execution.
3 Is there a good documentation and hopefully some architectural block diagram?
Xcode Version 16.0 (16A242d)
iOS18 - Swift
There seems to be a behavior change on iOS18 when using AppShortcuts and AppIntents to pass string parameters. After Siri prompts for a string property requestValueDialog, if the user makes a statement the string is passed. If the user's statement is a question, however, the string is not sent to the AppIntent and instead Siri attempts to answer that question.
Example Code:
struct MyAppNameShortcuts: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: AskQuestionIntent(),
phrases: [
"Ask \(.applicationName) a question",
]
)
}
}
struct AskQuestionIntent: AppIntent {
static var title: LocalizedStringResource = .init(stringLiteral: "Ask a question")
static var openAppWhenRun: Bool = false
static var parameterSummary: some ParameterSummary {
Summary("Search for \(\.$query)")
}
@Dependency
private var apiClient: MockApiClient
@Parameter(title: "Query", requestValueDialog: .init(stringLiteral: "What would you like to ask?"))
var query: String
// perform is not called if user asks a question such as "What color is the moon?" in response to requestValueDialog
// iOS 17, the same string is passed though
@MainActor
func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView {
print("Query is: \(query)")
let queryResult = try await apiClient.askQuery(queryString: query)
let dialog = IntentDialog(
full: .init(stringLiteral: queryResult.answer),
supporting: .init(stringLiteral: "The answer to \(queryResult.question) is...")
)
let view = SiriAnswerView(queryResult: queryResult)
return .result(dialog: dialog, view: view)
}
}
Given the above mock code:
iOS17:
Hey Siri
Ask (AppName) a question
Siri responds "What would you like to ask?"
Say "What color is the moon?"
String of "What color is the moon?" is passed to the AppIntent
iOS18:
Hey Siri
Ask (AppName) a question
Siri responds "What would you like to ask?"
Say "What color is the moon?"
Siri answers the question "What color is the moon?"
Follow above steps again and instead reply "Moon"
"Moon" is passed to AppIntent
Basically any interrogative string parameters seem to be intercepted and sent to Siri proper rather than the provided AppIntent in iOS 18
My app focuses on a particular day and in the app I have arrow buttons that let you switch to the next or previous day. When one of them is pressed I call WidgetCenter.shared.reloadAllTimelines(). Almost immediately, regardless of how many times they are pressed, I will usually see my widgets immediately update to reflect the new day.
I thought it would be nice to extend this functionality to Lock Screen controls. I had the AppIntent the Lock Screen buttons use call some of the same code that the arrow buttons in my app do, which includes a call to WidgetCenter.shared.reloadAllTimelines().
In the simulator it seemed to work great. I could see my Lock Screen widgets update almost immediately to focus on the new day.
However, when I tried it on an actual device it was a much different story. Usually the first button press will update the widgets but after that it can be much, much longer before the Lock Screen widgets eventually refresh.
It makes sense that the system is probably throttling my requests but is there a way to prevent this so that my Lock Screen controls operate the same way as buttons in my app?
The following code works perfectly fine in iOS 17, where I can retrieve the desired dependency value through @IntentParameterDependency as expected. However, in iOS 18, addTransaction always returns nil.
struct CategoryEntityQuery: EntityStringQuery {
@Dependency
private var persistentController: PersistentController
@IntentParameterDependency<AddTransactionIntent>(
\.$categoryType
)
var addTransaction
func entities(matching string: String) async throws -> [CategoryEnitity] {
guard let addTransaction else {
return []
}
// ...
}
func entities(for identifiers: [CategoryEnitity.ID]) async throws -> [CategoryEnitity] {
guard let addTransaction else {
return []
}
// ...
}
func suggestedEntities() async throws -> [CategoryEnitity] {
guard let addTransaction else {
return []
}
// ...
}
}
Has anyone else encountered the same issue? Any insights or potential workarounds would be greatly appreciated.
iOS: 18.0 (22A3354)
Xcode 16.0 (16A242d)
This is a follow up to this post about building a Control Center widget to open the app directly to a particular feature. I have it working in a sample app, but when I do the same thing in my full app I get this error:
[[com.olivetree.BR-Free::com.olivetree.BR-Free.VerseWidget:com.olivetree.BR-Free.ContinueReadingPlanControl:-]] Control action: failed with error: Error Domain=ChronoKit.InteractiveWidgetActionRunner.Errors Code=1 "(null)"
Google has nothing for any of that. Can anyone shed light on what it means?
This is my control and its action:
@available(iOS 18.0, *)
struct ContinueReadingPlanControl : ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "com.olivetree.BR-Free.ContinueReadingPlanControl") {
ControlWidgetButton(action: ContinueReadingPlanIntent()) {
Image(systemName: "book")
}
}
.displayName("Continue Reading Plan")
}
}
@available(iOS 18.0, *)
struct ContinueReadingPlanIntent : ControlConfigurationIntent {
static let title: LocalizedStringResource = "Continue Reading Plan"
static let description = IntentDescription(stringLiteral: "Continue the last-used reading plan")
static let isDiscoverable = false
static let opensAppWhenRun: Bool = true
@MainActor
func perform() async throws -> some IntentResult & OpensIntent {
let strUrl = "olivetree://startplanday"
UserDefaults.standard.setValue(strUrl, forKey: "StartupUrl")
return .result(opensIntent: OpenURLIntent(URL(string: strUrl)!))
}
}
Note also that I'm pulling this from Console.app, streaming the logs from my device. I don't know of a way to debug a Control Center widget in Xcode, though this thread implies that it's possible.
As a user, when viewing a photo or image, I want to be able to tell Siri, “add this to ”, similar to example from the WWDC presentation where a photo is added to a note in the notes app.
Is this... possible with app domains as they are documented?
I see domains like open-file and open-photo, but I don't know if those are appropriate for this kind of functionality?
Hi everyone.
I'm trying to use the new ControlWidget API introduced on iOS 18 to open a sheet that contains a form when the user taps on the button on the control center.
This is my current code. It opens the app, but I haven't found how to do an action inside the app when the app is opened.
@available(iOS 18, *)
struct AddButtonWidgetControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "com.example.myapp.ButtonWidget") {
ControlWidgetButton(action: LaunchAppIntent()) {
Label("Add a link", systemImage: "plus")
}
}
.displayName("Add a link")
.description("Creates a link.")
}
}
@available(iOS 18, *)
struct LaunchAppIntent: AppIntent {
static var title: LocalizedStringResource { "Launch app" }
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult {
return .result()
}
}
Hey all,
iOS 18 - RC
I have an app that supports both Widgets and ControlWidget, which resides on the same AppIntent.
The following sync works fine when any action is taken on any of the three players -
App - Widget - both directions - works as expected
App - Control Widget - both directions - works as expected
However -
Widget - ControlWidget - the UI not always sync in real time (the values are ok)
So if for instance I increase a counter on the widget from 1 to 2, the comtrolwidget will still show 1, but if I tap it, it will increase to 3.
For any update/action taken on the AppInten, I call -
WidgetCenter.shared.reloadAllTimelines()
ControlCenter.shared.reloadAllControls()
Any idea how to ensure this sync?
Thanks a lot!
Dudi
I have created an iOS 18 Control Center Widget that launches my app. However I am not able to detect it in AppDelegate.swift. I have created custom scheme funRun://beginRun in Target => Info => URL Types URL Types setup in Xcode
This method in AppDelegate.swift does not fire at all and I get this error in console:
Failed to open URL runFun://beginRun: Error Domain=NSOSStatusErrorDomain Code=-10814 "(null)" UserInfo={_LSLine=279, _LSFunction=-[_LSDOpenClient openURL:fileHandle:options:completionHandler:]}``
`
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// this does not fire
print("Scheme \(url.scheme)")
print("Host \(url.host)")
return true
}`
I tried this answer to no avail: iOS 18 Control Widget that opens a URL
Even adding EnvironmentValues().openURL(url) as suggested here did not help.
@MainActor
func perform() async throws -> some IntentResult & OpensIntent {
let url = URL(string: "funRun://beginRun")!
EnvironmentValues().openURL(url)
return .result(opensIntent: OpenURLIntent(url))
}
Here is my extension code: My goal is to detect the url string from the request, so I can decide which screen to launch from AppDelegate's open url method. When I test this with iOS 18 RC it does not work either in simulator or on real device
import AppIntents
import SwiftUI
import WidgetKit
@available(iOS 18.0, watchOS 11.0, macOS 15.0, visionOS 2.0, *)
struct StartRunControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(
kind: "name.funRun.StartRun",
provider: Provider()
) { value in
ControlWidgetButton("Hello",
action: MyIntent()) { hi in
Label("Start", systemImage: "sun.min.fill")
}
}
.displayName("Start run")
.description("Opens a run screen.")
}
}
@available(iOS 18.0, watchOS 11.0, macOS 15.0, visionOS 2.0, *)
extension StartRunControl {
struct Provider: ControlValueProvider {
var previewValue: Bool {
false
}
func currentValue() async throws -> Bool {
let isRunning = true // Check if the timer is running
return isRunning
}
}
}
@available(iOS 18.0, watchOS 11.0, macOS 15.0, visionOS 2.0, *)
struct MyIntent: AppIntent {
static let title: LocalizedStringResource = "My Intent"
static var openAppWhenRun: Bool = true
init() {}
@MainActor
func perform() async throws -> some IntentResult & OpensIntent {
let url = URL(string: "funRun://beginRun")!
EnvironmentValues().openURL(url)
return .result(opensIntent: OpenURLIntent(url))
}
}
I even checked info.plist and it seems okay.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>beginRun</string>
<key>CFBundleURLSchemes</key>
<array>
<string>funRun://beginRun</string>
</array>
</dict>
</array>
Does anyone know where the problem might be? Thanks!
Issue: unresolved variable(s) found: +applicationName
I don't know how to fix this warning. Also need help figuring out what the other warning is. All showed up after upgrading to Xcode 16.
Hi,
I have an existing app with AppEntities defined, that works on iOS16 and iOS17. The AppEntities also have EntityPropertyQuery defined, so they work as 'find intents'. I want to use the new @AssistantEntity on iOS18, while supporting the previous versions. What's the best way to do this?
For e.g. I have a 'person' AppEntity:
@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *)
struct CJLogAppEntity: AppEntity {
static var defaultQuery = CJLogAppEntityQuery()
....
}
struct CJLogAppEntityQuery: EntityPropertyQuery {
...
}
How do I adopt this with @AssistantEntity(schema: .journal.entry) for iOS18, while maintaining compatibility with iOS16 and 17?
To support AppIntent in our app, we plan to follow the same approach as the “Get Details of Reminders” Shortcut Action in the Reminders app, as recommended in this WWDC session (https://developer.apple.com/wwdc24/10176?time=166). The goal is to allow querying all properties of an entity—referred to as “Node” in our app—using a single, configurable intent. For instance, we want one intent that can query properties like “Title,” “Background Color,” and “Font Name” for a specific node.
However, since the returned properties have varying data types, this setup requires flexible return types in the perform implementation of our “Get Details” intent. The challenge is that the AppIntent protocol mandates the use ReturnsValue one associated type as the result of perform. For example, we can use ReturnsValue<String> to retrieve the “Title” property, but this would restrict us from using ReturnsValue<Color> for the “Background Color” property.
What’s the best approach for implementing an Intent where the return types vary based on the input parameters provided?
Hello,
I'm preparing my app Tameno for iOS 18, adding a couple of Control Center widgets.
One of them allows users to select their favorite interval. But in the context of my app, only seconds and minutes make sense as a unit value - I don't need milli-pseconds, nor hours.
Is there a way restrict these available options that come from a ControlConfigurationIntent?
@available(iOS 18.0, iOSApplicationExtension 18.0, *)
struct TamenoFavoriteIntervalControlWidgetSetupIntent : ControlConfigurationIntent {
static let title: LocalizedStringResource = "cw_FavoriteIntervalSetup"
static let isDiscoverable: Bool = false
@Parameter(title: "cw_IntervalParameter", defaultValue: 5.0, defaultUnit: .seconds, supportsNegativeNumbers: false) var interval: Measurement<UnitDuration>?
@MainActor
func perform() async throws -> some IntentResult {
.result()
}
}
I am able to restrict it just to seconds or minutes only (by adding unit: .seconds, or unit: .minutes to the @Parameter setup), but I'd really like to offer both.
Thank you,
Matthias
使用APPIntent 的AppShortcutsProvider方式,最多只能添加10个AppShortcut,超过10个,代码编译就会报错
struct MeditationShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: StartMeditationIntent(),
phrases: [
"Start a (.applicationName)",
"Begin (.applicationName)",
"Meditate with (.applicationName)",
"Start a (.$session) session with (.applicationName)",
"Begin a (.$session) session with (.applicationName)",
"Meditate on (.$session) with (.applicationName)"
]
)
}
}
如何能做到像特斯拉APP一样
After building my app with Xcode 16 beta 6 I'm getting this warning in my AppIntents.
Encountered a non-optional type for parameter: computer. Conformance to the following AppIntent protocols requires all parameter types to be optional: AppIntents.WidgetConfigurationIntent, AppIntents.ControlConfigurationIntent
The intent looks something like this
struct WakeUp: AppIntent, WidgetConfigurationIntent, PredictableIntent {
@Parameter(title: "intent.param.computer", requestValueDialog:"intent.param.request_dialog.computer")
var computer: ComputerEntity
init(computer: ComputerEntity) {
self.computer = computer
}
init() {
}
public static var parameterSummary: some ParameterSummary {
Summary("Wake Up \(\.$computer)")
}
static var predictionConfiguration: some IntentPredictionConfiguration {
IntentPrediction(parameters: (\.$computer)) { computer in
DisplayRepresentation(
title: "Wake Up \(computer)"
)
}
}
@MainActor
func perform() async throws -> some IntentResult & ProvidesDialog {
}
}
According to the docs though specifying optional is how we say if the value is required or not. https://developer.apple.com/documentation/appintents/adding-parameters-to-an-app-intent#Make-a-parameter-optional-or-required
So is this warning accurate? If so, how do I specify that a parameter is required by the intent now?