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

177 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Action Button on Apple Watch Ultra 2 calls shortcut twice
Has anyone else seen this issue? When the Action Button on an Apple Watch Ultra 2 is connected to a Shortcut, it seems to run the shortcut twice. I'm on watchOS 10.0.2. A user of an app I built reported the issue, which is how I knew about it in the first place. I'm wondering if it's an issue on my watch specifically, or if many other people are seeing the same thing. I replicated the issue using a fresh project, and it only seems to happen when the shortcut responds with dialog. Does anyone know why this is happening and how to fix it? The shortcut with a dialog response works fine everywhere else, and only exhibits this behavior when run with the Action Button. Here is the full code with instructions to replicate the issue, so I'm curious if other people see the same thing: // When running a shortcut that returns dialog // with the Apple Watch Ultra Action Button, // the shortcut runs twice. // Create a new iOS project and add this: import AppIntents // AppIntent struct LogEventNow: AppIntent { static var title: LocalizedStringResource = "Log an Event" @MainActor func perform() async throws // -> some IntentResult // When just returning a successful result with .result(), // the shortcut only runs once as expected // Add ProvidesDialog to be able to return .result(dialog:) -> some IntentResult & ProvidesDialog { let loggedDate = Date() let formattedLoggedDate = loggedDate.formatted(date: .omitted, time: .complete) // Print the time of the event that was logged print(formattedLoggedDate) // This gives the expected result // Shortcut runs once, and prints one time to the console // return .result() // This gives unexpected result // Shortcut seems to run twice // and prints two date a 1–2 seconds apart return .result(dialog: "Successfully logged.") } } // AppShortcut // This makes it show up in the Shortcuts app struct EventShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: LogEventNow(), phrases: ["Log in \(.applicationName)"], shortTitle: "Log Event Now", systemImageName: "calendar" ) } } // Steps to reproduce the issue: // - Long press the AppShortcut in Shortcuts app // - Tap "Add to Shortcut" // - Tap the "i" at the bottom // - Turn on "Show on Apple Watch" toggle // - Open the Watch app on iPhone // - Tap "Action Button" // - Under "Action" choose "Shortcut" // - Select the Shortcut that was created in the Shortcuts app // - Push the Action Button and observe two dates printed to the console // Sometimes I'm also seeing "Remote execution timed out" on Apple Watch a minute or so after the shortcut has run, but only when leaving the Shortcuts app open after it runs from the Action button.
1
0
800
Oct ’23
WidgetConfiguration with AppEnum and When clausole on AppIntent
Hi there, I'm trying to use an enum as a @Parameter for my Widget configuration: enum InteractivePlacesWidgetMode: Int, CaseIterable, AppEnum, Comparable, Equatable { typealias RawValue = Int case favourites = 0, recents, nearbyCategory, collections static var typeDisplayRepresentation: TypeDisplayRepresentation = TypeDisplayRepresentation(name: LocalizedStringResource("Mode")) static var caseDisplayRepresentations: [InteractivePlacesWidgetMode: DisplayRepresentation] = [ .favourites: DisplayRepresentation(title: LocalizedStringResource("Favorites")), .recents: DisplayRepresentation(title: LocalizedStringResource("Recents")), .nearbyCategory: DisplayRepresentation(title: LocalizedStringResource("Categories")), .collections: DisplayRepresentation(title: LocalizedStringResource("Collections")) ] static func < (lhs: InteractivePlacesWidgetMode, rhs: InteractivePlacesWidgetMode) -> Bool { lhs.rawValue < rhs.rawValue } static func == (lhs: InteractivePlacesWidgetMode, rhs: InteractivePlacesWidgetMode) -> Bool { lhs.rawValue == rhs.rawValue } } Then on the ConfigurationAppIntent I would like to show some more option only for specific cases, with the following: struct ConfigurationAppIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Configuration" static var description = IntentDescription("Choose what to show") @Parameter(title: LocalizedStringResource("Show"), default: .favourites) var widgetMode: InteractivePlacesWidgetMode @Parameter (title: "Category") var category: CategoryDetail? static var parameterSummary: some ParameterSummary { When(\.$widgetMode, .equalTo, .nearbyCategory) { Summary { \.$widgetMode \.$category } } otherwise: { Summary { \.$widgetMode } } } } But the widget seems to ignore the When clausole at all. Is this a limitation of the When clausole? Is there something wrong with my approach? I already used that with standard types in previous work and it seems to work quite well. Thanks in advance for your help. c.
1
0
607
Oct ’23
AppIntentsPackage protocol with SPM package not working
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 !
11
3
2.8k
Oct ’23
Siri Watch Face and RelevantIntentManager
I am trying to add a watch widget that I've created for Smart Stack feature of watchOS 10 to also appear in the list of shortcuts shown in the Siri Watch Face. It seems like Apple now wants us to use RelevantIntentManager for this purpose, but my widget never shows up in the Siri Watch face. This is the code that I am using. func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<GenericEntry> { [...] await updateRelevantIntents() return timeline } func updateRelevantIntents() async { var relevantIntents = [RelevantIntent]() let defaults = UserDefaults.init(suiteName: "group.tesla.watch.maadotaa")! guard let name2VIN = defaults.dictionary(forKey: Constants.VEHICLE_NAME_VIN_DICT) as? [String:String] else { return } let carNames = Array(name2VIN.keys) for (idx, name) in carNames.enumerated() { let intent = ConfigurationAppIntent() intent.order = idx intent.carName = name intent.action = nil let txt = "\(name): info only" let relIntent = RelevantIntent(intent, widgetKind: "WatchWidget", relevance: RelevantContext.date(from: .now, to: .now + 3600 * 1)) relevantIntents.append(relIntent) } do { try await RelevantIntentManager.shared.updateRelevantIntents(relevantIntents) } catch (let error) { print("\(#function): \(error.localizedDescription)") } }
1
0
492
Oct ’23
Can't start Live Activity from App Intent if another LA already started
A have a few App intents that conforms to LiveActivityStartingIntent. If there are no active LA, then any of my intents can start live activity. But if there is at least one active LA then requesting LA returns an error: "The operation couldn’t be completed. Target is not foreground" Is there a limit to only 1 LA or I do something wrong?
1
0
633
Sep ’23
AppIntents - Issue with perform() method return types
Hi there, I'm migrating my old Intents to the new App Intents framework. I have an intent that always returns a dialog, but never returns a value. Therefore I define the return types for its perform method as follows: func perform() async throws -> any IntentResult & ProvidesDialog When running the intent, the app crashes and the debugger indicates AppIntents/PerformActionExecutorTask.swift:195: Fatal error: perform() returned types not declared in method signature - Did not declare ProvidesDialog but provided one perform() returned types not declared in method signature - Did not declare ProvidesDialog but provided one The actual expression for returning a result is written as follows: return .result(dialog:"hello world") I tried a few alternative return types definition with no luck. I'm on XCode 15.0 (15A240d) and running on iOS 17.0 (21A329) Running out of ideas...
1
2
953
Sep ’23
App Shortcut "Couldn't find AppShortcutsProvider"
I am trying to create a shortcut following "Implement App Shortcuts With App Intents" talk from WWDC2022. The below is my MWE. In a standalone app, this can be extended and behave like the video. Adding this code to my main app, makes the shortcut show up within the Shortcuts app, but if I click on it, it pops up an alert saying Error Domain=LNActionForAutoShortcutPhraseFetchError Code=1 "Couldn't find AppShortcutsProvider" UserInfo={NSLocalizedDescription=Couldn't find AppShortcutsProvider} My main app has several targets, so I suppose I need to establish which one is the shortcuts provider, but I cannot find any reference to how to do this in the documents. Via Siri, the shortcut command is not recognised at all. import AppIntents import SwiftUI struct DoSomething: AppIntent {  static var title: LocalizedStringResource = "Do something"  func perform() async throws -> some IntentResult {   return .result()  }  static var openAppWhenRun: Bool = false } struct MyShortcuts: AppShortcutsProvider {  @AppShortcutsBuilder  static var appShortcuts: [AppShortcut] {   AppShortcut(    intent: DoSomething(),    phrases: ["Do Something in \(.applicationName)"],    systemImageName: "books.vertical.fill"   )  } }
5
1
2.4k
Sep ’23
iOS 17 App Intent Widget → How do i make a filler when their is no information in the intent data?
Hi! I'm working on a widget using the new app intent & widgetkit features. Until now everything works, but I can't figure out how to give for example a line of text or a dummy data when the intent data is empty. For example in the Widgetsmith app, you can put pictures on your homescreen using widgets. But from the moment that you delete the picture in the app, the widget changes to a text screen where they have placed information about changing the widget to another option. Can you help me? My code so far: // // TimersIntentWidget.swift // // Created by Mees Akveld on 25/09/2023. // import Foundation import AppIntents import WidgetKit import SwiftUI @available(iOS 17, *) struct PresetIntentWidget: AppIntentTimelineProvider { func timeline(for configuration: selectPresetIntent, in context: Context) async -> Timeline<PresetEntry> { let entry = PresetEntry(date: Date(), presetModel: configuration.preset) let timeline = Timeline(entries: [entry], policy: .never) return timeline } func snapshot(for configuration: selectPresetIntent, in context: Context) async -> PresetEntry { PresetEntry(date: Date(), presetModel: configuration.preset) } func placeholder(in context: Context) -> PresetEntry { PresetEntry(date: Date(), presetModel: WidgetPreset.allPresets[0]) } } @available(iOS 17, *) struct PresetEntry: TimelineEntry { let date: Date let presetModel: WidgetPreset } @available(iOS 17, *) struct PresetWidgetView: View { let entry: PresetEntry private func isColorTheme() -> Int { let defaults = UserDefaults(suiteName: "group.MeesAkveld.ShareDefaults") let colorTheme = defaults?.integer(forKey: "ColorTheme") ?? 1 if colorTheme == 0 { return 1 } else { return colorTheme } } var body: some View { GeometryReader { geometry in ZStack { Image("bannerT\(isColorTheme())_Small") .resizable() .aspectRatio(contentMode: .fill) .scaleEffect(1.11) HStack { Rectangle() .cornerRadius(20) .frame(width: geometry.size.width - 20, height: geometry.size.height - 20, alignment: .center) .foregroundStyle(customBlue2Func()) Spacer() } .padding(.leading, 10) HStack { VStack(alignment: .leading, spacing: 10) { Image(systemName: entry.presetModel.icon != "" ? entry.presetModel.icon : "timer") .font(.system(size: 30)) .multilineTextAlignment(.center) .frame(width: 18) .offset(x: 10) VStack(alignment: .leading){ Text(entry.presetModel.title != "" ? entry.presetModel.title : "") .bold() Text(timeToText(hours: entry.presetModel.hours, minutes: entry.presetModel.minutes, seconds: entry.presetModel.seconds)) } .lineLimit(entry.presetModel.id == "noPresets" ? 2 : 1) } .foregroundColor(customBlueFunc()) Spacer() } .padding(25) } .widgetURL(URL(string:"preset:///\(entry.presetModel.id)")) } } } @available(iOS 17, *) struct PresetWidgetConfiguration: Widget { var body: some WidgetConfiguration { AppIntentConfiguration( kind: "presetWidgetIntent", intent: selectPresetIntent.self, provider: PresetIntentWidget() ) { entry in PresetWidgetView(entry: entry) } .configurationDisplayName("Presets") .description("View and activate a preset of your choosing from your homescreen.") .contentMarginsDisabled() .supportedFamilies([.systemSmall]) } } @available(iOS 17, *) struct PresetIntentWidget_Previews: PreviewProvider { static var previews: some View { PresetWidgetView(entry: PresetEntry(date: Date(), presetModel: WidgetPreset(id: "", title: "Title", icon: "", hours: 1, minutes: 1, seconds: 1, showEditView: false))) } } @available(iOS 17, *) struct WidgetPreset: AppEntity, Decodable { var id: String var title: String var icon: String var hours: Int var minutes: Int var seconds: Int var showEditView: Bool static var typeDisplayRepresentation: TypeDisplayRepresentation = "Preset" static var defaultQuery = WidgetPresetQuery() var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(title)", subtitle: "\(timeToText(hours: hours, minutes: minutes, seconds: seconds))") } static var allPresets: [WidgetPreset]{ get { let defaults = UserDefaults(suiteName: "group.MeesAkveld.ShareDefaults") let presetsData = defaults!.data(forKey: "presets") if let data = presetsData, let loadedPresets = try? JSONDecoder().decode([WidgetPreset].self, from: data) { return loadedPresets } else { return [] } } } } @available(iOS 17, *) struct WidgetPresetQuery: EntityQuery { func entities(for identifiers: [WidgetPreset.ID]) async throws -> [WidgetPreset] { WidgetPreset.allPresets.filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [WidgetPreset] { WidgetPreset.allPresets } func defaultResult() async -> WidgetPreset? { WidgetPreset.allPresets.first } } @available(iOS 17, *) struct selectPresetIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Preset" static var description: IntentDescription = IntentDescription("Select a preset") @Parameter(title: "Selected preset:") var preset: WidgetPreset }
0
1
862
Sep ’23
Interactive widgets in Standby without unlocking phone
I'm currently implementing interactive widgets for my app. The widget calls an intent that is also used by Shortcuts and this interaction seems to work with no issues. Now I'm looking to get that running in Standby and on the lockscreen with the phone locked. I figured static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed would do the trick, but the phone still asks to be unlocked before running the intent. Is there any way to get this working? I've seen some examples for widgets that can be run with the phone locked, but they all seem to be audio intents that play some audio. Example of the intent code:
0
0
402
Sep ’23
App Intent incorrectly parses milliliters as megaliters in the en-GB environment
Hello, I just discovered that on iOS 17.0 (release), if Measurement<UnitVolume> is used in App Intent, the system will incorrectly parse mL (milliliters) as megaliters. They differ by 9 orders of magnitude. This issue only occurs in the English + United Kingdom regional format. Sample code: https://github.com/gongzhang/AppIntentUnitVolumeBugUnderEnGB Screen recording: https://youtu.be/rMMAHOFpPXs
1
0
427
Sep ’23
Using Core Location in App Intent
I would like to retrieve the user's current location when they are logging some information with my App Intent. When the app has been just run, this works just fine, but if it has been force quit or not run recently, the Core Location lookup times out. I have tried logging the information and using the Core Location background mode, and I can verify that the background mode is triggering because there is an indicator on the status bar, but the background mode does not seem to fire the delegate. Is there a good way to debug this? When I run the app, everything works just fine, but I can't confirm that delegate calls are going through because I can't debug from an App Intent launch. Here is the perform method from my App Intent func perform() async throws -> some ProvidesDialog { switch PersistenceController.shared.addItem(name: name, inBackground: true) { case .success(_): return .result(dialog: "Created new pin called \(name)") case .failure(let error): return .result(dialog: "There was a problem: \(error.localizedDescription)") } } addItem calls LocationManager.shared.getCurrentCoordinates: func getCurrentCoordinates(inBackground: Bool = false, callback: @escaping (CLLocation?) -> Void) { if lastSeenLocation != nil { callback(lastSeenLocation) return } if inBackground { locationManager.allowsBackgroundLocationUpdates = true locationManager.showsBackgroundLocationIndicator = false } let status = CLLocationManager.authorizationStatus() guard status == .authorizedAlways || status == .authorizedWhenInUse else { DispatchQueue.main.async { [weak self] in self?.callback?(nil) self?.locationManager.allowsBackgroundLocationUpdates = false } return } self.callback = callback locationManager.startUpdatingLocation() } The CLLocationManager delegate didUpdateLocations then calls the callback with the location and sets allowsBackgroundLocationUpdates to false. And the callback saves the location data to Core Data. What is the best practice for using Core Location in an App Intent?
0
0
462
Sep ’23
IntentDonationManager not donating Shortcuts
if #available(iOS 16.0, *) {       print("donated")       let intent = BasicIntent()       IntentDonationManager.shared.donate(intent: intent)    } Trying to test if donations work with the new App Intents framework. Donating the shortcut once a user taps a button. The shortcut is not appearing on the lock screen. Everything else is working as expected. The Shortcut is appearing in the Shortcuts App and is working via Siri. In developer settings I have Display Recent Shortcuts -> On Display Donations on Lock Screen -> On Allow Any domain -> On Allow Unverified sources -> On Running iOS 16.2, iPhone 11.
4
2
1.6k
Sep ’23
Journaling Suggestions API ETA?
hi there, one of the features I'm most looking forward to as a developer and a user is the journaling app. I'm assuming the app won't make the initial iOS17 launch next week, but I was wondering if there was an idea on when the APIs might be available to start working with? “Journaling Suggestions API” means the Documented API that enables a display of journaling suggestions. (from https://developer.apple.com/support/terms/apple-developer-program-license-agreement/) cheers, Mike
3
0
1.5k
Sep ’23
Unable to call code inside App Intent Extension like updateAppShortcutParameters() - Linking error
Was watching this latest WWDC 2023 video and had a question. I see about 17:20 in, they mention you can now put the shortcut provider in an app intent extension. https://developer.apple.com/videos/play/wwdc2023/10103/ This works fine by itself and I can see all my shortcuts and use siri, but as soon as I try to call into the extension from the main app in order to trigger updateAppShortcutParameters() or any other code, I get a linker error. Am I doing something obvious wrong? Note, I called it a framework, but it Is just an extension. Cant figure out how I am supposed to be calling this method. Any help is greatly appreciated! https://developer.apple.com/documentation/appintents/appshortcutsprovider/updateappshortcutparameters()?changes=_4_8 https://imgur.com/a/yDygSVJ
0
0
530
Sep ’23
Is there any way to expose an AppIntent that lives in the app package or an AppIntentExtension to a widget?
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!
6
5
2.1k
Sep ’23
Can I trigger app specific shortcut using Siri on any language except English?
My concern is that I am not able to run the app specific shortcut (which is available to develop on iOS 16/ iOS 17) on any other language except English using Siri. I’m facing the issue when I say : “Siri do A” and Siri founds the similar shortcut in the iOS (not in the my app) and runs it. on English everything works well, but on Russian ( for example) I am facing the described above issue. How can I fix it?
0
0
421
Sep ’23