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

ControlWidget jump deep link and custom icon error
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...
1
0
248
Sep ’24
SwiftData ignore changes on App Intents
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!
2
0
396
Sep ’24
Change in iOS 18 prevents SwiftData synchronization between main app and extension
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?
1
0
401
Sep ’24
iOS 18: Siri not passing string parameters to AppIntents if the string is a question
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
1
0
474
Oct ’24
Problems trying to call reloadAllTimelines() multiple times from an AppIntent
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?
0
0
168
Sep ’24
@IntentParameterDependency Always Returns nil in iOS 18
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)
2
2
378
Oct ’24
What is ChronoKit.InteractiveWidgetActionRunner.Errors Code 1?
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.
2
0
445
Sep ’24
Open an specific view or sheet of the app from a control widget button
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() } }
2
0
322
Sep ’24
AppIntent - Widget & ControlWidget
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
1
0
383
Sep ’24
Open specific screen in App Delegate after iOS 18 Control Center widget is tapped (failed to open URL)
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!
1
0
509
Sep ’24
Using AssistantEntity with existing AppEntities for iOS17
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?
0
0
363
Sep ’24
AppIntent with flexible return types
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?
1
0
342
Sep ’24
Restricting available units for a Measurement<UnitDuration> @Parameter
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
3
0
351
Sep ’24
如何在安装APP后,可以在系统的快捷指令APP中直接看到并使用超过10个以上的自定义快捷指令
使用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一样
1
1
348
Oct ’24
Non Optional AppIntent Param
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?
3
8
502
4d