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

App Intents Extension doesn't work when changing bundle identifier
Recently I realized that even though I was able to add my app's intents in the Shortcuts app, selecting any of the parameters didn't show the popup list of suggestions (the ones declared by DynamicOptionsProvider in the AppIntent subclass) and running it showed an error. In the image you can see the two suggestions for the working app version ("asdf" and "bla") that would not be there in the non-working version. I knew that when I had added this functionality, it worked, so I found the app version that caused the App Intents Extension to stop working. Apparently, the problem was that I had removed the Swift files declared in the app extension from my main app's target. Probably when I first added the App Intents Extension I had noticed that adding the extension's source files to the main target made it work, but later thought that it shouldn't be necessary and didn't test if it still worked. Today I created an empty project with a new App Intents Extension and confirmed that the Shortcuts app was correctly showing the parameter popup suggestions, even without including the extension's source files in the main target. Then during the course of almost an entire day I gradually reduced my original Xcode project to this new sample project to find what else would make the extension work, other than including the extension's source files in the main target. My very last resource was changing the bundle identifier, which solved the issue. My original project's targets have identifiers like org.domain.OriginalApp and org.domain.OriginalApp.AppIntent, while the sample project's targets have identifiers like org.domain.SampleApp and org.domain.SampleApp.AppIntent. How could including the App Intents Extension's source files in the main target or changing the bundle identifiers cause the Shortcuts app to correctly show the parameter popup suggestions?
0
0
500
Feb ’24
Get the creation date of an IntentFile
Is it possible to get the original date created for an IntentFile? The following code always gets the date for right now, surely because it's copied into a temporary directory so that's when it was created at that location. if let fileURL = file.fileURL, fileURL.startAccessingSecurityScopedResource() { if let attributes = try? FileManager.default.attributesOfItem(atPath: fileURL.path), let date = attributes[.creationDate] as? Date { print(date) } fileURL.stopAccessingSecurityScopedResource() }
0
0
354
Feb ’24
iOS AppIntents “Unable to determine value type for type” when AppEnum belongs to Swift Package
Sorry if I'm in the wrong category for this :pray: Please see this MRE for clarity: https://github.com/MartinP7r/IntentTest (I used the example code from https://developer.apple.com/wwdc22/10032 except for deprecation warnings) The compiler throws an error Unable to determine value type for type IntentPackage.Shelf. According to comments in this question it's because the type I'm extending to AppEnum is not in the app target's module, but in a Swift Package. And yes, copying Shelf into the target will solve the issue, but I really don't like having to duplicate the types just to make it work and was wondering if there's any way to just use the type from the Swift package and only add the AppEnum conformance in the main target.
1
0
279
Feb ’24
Dynamic app shortcuts using AppShortcutsProvider and configurable AppIntent
Hello everyone, I want to add preconfigured app shortcuts for my app using an AppShortcutsProvider implementation. I have been following this demo from WWDC22: https://developer.apple.com/wwdc22/10170 All looks pretty straight forward. However, I would like the preconfigured shortcuts to be based on the state of the data in the app: adding one shortcut for every user-entered item in a list. Now, this might be due to the fact that I'm a Swift novice, but I can't figure out how to do that from a AppShortcutsBuilder property as I can't create the AppShortcut instances in a for loop. I have failed to find any resources online on this. I assume I would need the ForEach equivalent of the ViewBuilder? Is anything like that available for AppShortcutsBuilder? I have also stumbled on this: https://developer.apple.com/documentation/sirikit/offering_actions_in_the_shortcuts_app But this solution seems to only work with INIntents rather than AppIntents. Is there a setShortcutSuggestions equivalent for AppIntents that I could call when the contents of my list change?
2
0
823
Jan ’24
Shortcut: Not able to perform() throws --> some ReturnsValue<Image>
Hello Community, I recently started to work on shortcuts with AppIntent and I want to have an image output on my shortcut action. The output of a string is simple and working: func perform() async throws -> some IntentResult & ReturnsValue<String> { let myString : String = "Hello World" return .result(value: myString) I am having trouble to return an image. Ideally I want to load an image from iCloud Drive or from a website and throw image result. I tried func perform() async throws -> some IntentResult & ReturnsValue<Image> { and func perform() async throws -> some IntentResult & ReturnsValue<INFile> { , but was not apple to write a proper code to return .result(value: myImage) . Any help is very welcome and highly appreciated. Have a good week Eric
0
0
305
Jan ’24
Asking Location Permission is not working on the AppIntents
@MainActor perform() async throws -> some IntentResult { // ... switch locationManager.authorizationStatus { case .denied, .restricted: throw UserLocationError.permissionDenied case .notDetermined: await locationManager.requestWhenInUseAuthorization() // to ask permission default: break } // ... } Here is my code. When the authorizationStatus is .notDetermined, it invokes requestWhenInUseAuthorization() method on the main thread, but throws UserLocationError.permissionDenied immediately, eventhough I didn't deny the permission. It's really weird and unexpected that it throws UserLocationError.permissionDenied when the status is not .denied or .restricted Even it invokes requestWhenInUseAuthorization(), there's no alert for asking permission If there's any solution, please let me know
0
0
374
Jan ’24
Siri Shortcuts, Sonoma, iOS 17 "No Flexible Matching Assets"
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?
5
4
950
Dec ’23
Help with Widget Configuration
Hello, I'm working on my first app. It's also my first encounter with App Intents. I have a data structure for events that has an ID (String), a name (String), a Date and an image (Data). The user can create them in the app and they are stored with CoreData. I wanted to have a widget that would allow the user to choose from their list of events and display that event in the widget. The list should appear in the widget configuration and it would be a list of the names and (if possible) the image. I think I have found how to access the information from the widget, but I cannot figure out how to have the list appear in the configuration. I have been following this guide: https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget?utm_source=pocket_saves. But that one shows hardcoded elements in the list and I haven't been able to find how to have the list change in relation to the content of the app. This is what I have made so far in the AppIntent file: import WidgetKit import AppIntents import CoreData struct EventDetail: AppEntity { static var defaultQuery: EventQuery = EventQuery() var id: String var date: Date var image: Data var title: String static var typeDisplayRepresentation: TypeDisplayRepresentation = "Event" var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(id) \(title)") } } struct EventQuery: EntityQuery{ func entities(for identifiers: [EventDetail.ID]) async throws -> [EventDetail] { return fill_event_details(events_list: getEventDataIntent()) } func suggestedEntities() async throws -> [EventDetail] { fill_event_details(events_list: getEventDataIntent()).filter { $0.id != "-" } } func defaultResult() async -> EventDetail? { try? await suggestedEntities().first } } struct ConfigurationAppIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Select an event" static var description = IntentDescription("This is an example widget.") // An example configurable parameter. @Parameter(title: "Event") var event: EventDetail // init(events: [UserCountdowns]) { // self.event = fill_event_details(events_list: events)[0] // print("AppIntent") // print(self.event.title) // } init() { } } func fill_event_details(events_list: [UserCountdowns]) -> [EventDetail] { var entities_list: [EventDetail]? let events = getEventDataIntent() for event in events { entities_list!.append(EventDetail(id: event.id!, date: event.date!, image: event.image!, title: event.title!)) } return entities_list ?? [EventDetail(id: "-", date: Date(), image: Data(), title: "empty")] } func getEventDataIntent() -> [UserCountdowns] { let context = PersistenceController.shared.container.viewContext let request = UserCountdowns.fetchRequest() var result: [UserCountdowns]! do { result = try context.fetch(request) } catch { print(error) } return result } I have been trying a few things in the widget's code but I haven't been able to make anything work, so I don't really have anything worth sharing, I think. This is the code for the UserCountdowns structure: extension UserCountdowns { @nonobjc public class func fetchRequest() -> NSFetchRequest<UserCountdowns> { return NSFetchRequest<UserCountdowns>(entityName: "UserCountdowns") } @NSManaged public var date: Date? @NSManaged public var image: Data? @NSManaged public var title: String? @NSManaged public var id: String? } Could anyone help me with this, please? What am I missing or what would the next step be? Let me know if there is any other part of the code I should share. Thank you in advance!
0
0
556
Dec ’23
iOS 17.2 breaking AppIntents and shortcuts
I have an app that relies heavily on AppIntents and Shortcuts and it seems like the latest iOS update broke those but I can't quite figure out what's the issue. The is that no matter what parameter I pick, when running the shortcut it always uses the defaultResult() Here's an example AppEntity: struct IntentBrokerAppEntity: AppEntity { static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Intent Broker") @Property(title: "Name") var name: String? @Property(title: "Ip") var ip: String? @Property(title: "Port") var port: String? @Property(title: "Username") var username: String? @Property(title: "Password") var password: String? @Property(title: "Tls") var tls: Bool? struct IntentBrokerAppEntityQuery: EntityQuery { func entities(for identifiers: [IntentBrokerAppEntity.ID]) async throws -> [IntentBrokerAppEntity] { return try await suggestedEntities().filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [IntentBrokerAppEntity] { let context = PersistenceController.shared.viewContext let brokerService = BrokerService(context: context) return brokerService.getFavorites().map { IntentBrokerAppEntity(broker: $0) } } func defaultResult() async -> IntentBrokerAppEntity? { try? await suggestedEntities().first } } static var defaultQuery = IntentBrokerAppEntityQuery() var id: String // if your identifier is not a String, conform the entity to EntityIdentifierConvertible. var displayString: String var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(displayString)") } ... This used to work perfectly fine before 17.2, but now instead of choosing the entity the user picked it always falls back to defaultEntity(). In the console I get this warning Failed to build EntityIdentifier. IntentBrokerAppEntity is not a registered AppEntity identifier But I'm not sure if that's related. Does anyone have any ideas on what's going on here? Input much appreciated!
3
3
890
Dec ’23
App Shortcuts with parameterized phrases not working
When using just the application name in a phrase, it works great and the shortcut can be invoked via Siri: e.g. "Show books in \(.applicationName)" // This works But introducing a parameter in a phrase fails to create a working shortcut that can be invoked via Siri: e.g. "Show \(\.$book) in (\.applicationName)" // Does not work where $book is a parameter for BookEntity in my intent. i am calling updateAppShortcutParameters() and i only have a single book titled "Frankenstein". When my App is launched after a fresh install, i can see that a shortcut is automatically created in the Shortcuts App but has the following title: "Show %@ in MyAppName" Even though the title looks incorrect, tapping the shortcut works and the correct book title is passed to my Intent. However, i cannot invoke the shortcut using Siri. i.e. saying "Show Frankenstein in MyAppName" does not work. Has anyone run into this particular issue? i am running Xcode 14 Beta 6 and iOS 16 Beta 7 on my iPhone. Also tested in iOS Simulator and got the same results. This is arguably the biggest selling point for App Shortcuts (zero setup required by the user) so i am hoping it is addressed before iOS 16 becomes officially available.
9
3
3.1k
Dec ’23
AppShortcuts limit for 10 shortcuts
Hi, according this WWDC session https://developer.apple.com/wwdc22/10170 App Shortcuts are defined in Swift code, by implementing the AppShortcutsProvider protocol. To implement the protocol, I'll simply create a single getter that returns all the app shortcuts I want to set up for the user. Note that in total, your app can have a maximum of 10 app shortcuts. However, most apps only need a few. there is a limit for up to 10 AppShortcuts. Could you please clarify how that limit handled? 🤔 (e.g. project failed to build / app will crash or malfunction / only 10 shortcuts will be handled on random/ordered choice by iOS) I suppose there is some way to manage shortcuts amount but see no details at documentation yet.
5
1
2.3k
Dec ’23
App Intents do not appear in macOS Shortcuts app
I've created a barebones Multiplatform app and added an App Intent and App Shortcut. When running on iOS, I can see my app show up in Shortcuts and use the intent or App Shortcut as normal. On macOS, my app does not appear in the Shortcuts app, neither the App Shortcut nor the intent. Is there additional configuration required to enable Shortcuts / App Intents on macOS? This is the only code I've added to a brand-new Xcode Multiplatform project: import AppIntents struct OpenIntent: AppIntent { static let title: LocalizedStringResource = "Open MacShortcut" static let description: LocalizedStringResource = "Opens the app" /// Launch your app when the system triggers this intent. static let openAppWhenRun: Bool = true /// Define the method that the system calls when it triggers this event. @MainActor func perform() async throws -> some IntentResult { /// Return an empty result since we're opening the app return .result() } } struct MacShortcutShortcutsProvider: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: OpenIntent(), phrases: [ "Open a session of \(.applicationName)" ], shortTitle: "Open", systemImageName: "arrow.up.circle.fill" ) } }
0
0
469
Dec ’23
iOS Share Activity - Add Custom Actions
See the image attached. What are the APIs needed to add an action here that shows up across the system. Not a share extension, but the list of actions that are below that. How did Pinterest add theirs here? And it shows up for almost everything you share. I've been looking around and the only thing that looked like maybe is UIActivity. But when I implemented it doesn't show up across other apps. I was also lookin through app shortcut and app intent documentation but I can't find exactly how Pinterest is providing this action here.
1
0
625
Dec ’23
How can I pause iOS Shortcut automation programmatically
I want to "pause" an Intent ( iOS Shortcut Automation ) how can I achieve it? Basically we have a small task to execute, whenever we setup an automation for one app, lets say LinkedIn, our app runs and asks the user whether they still want to continue with LinkedIn or whether they don't want to. The automation to open our app when LinkedIn is opened is working fine. What we want to achieve is that once a user taps on "Continue to LinkedIn" it should "pause" the automation this time and open LinkedIn instead of opening our app again.
0
0
517
Dec ’23
Opening an App Conditionally with Swift and App Intents in iOS Shortcuts
I am trying to create a simple app that "blocks" other apps if a certain condition is not met. I am currently using the IOS shortcuts and have set up an automation that opens my app A whenever another app B opens. If the condition is not met i imagine the flow to look like: Open app A. My app B opens instead. I check a box in my app B. I navigate back to app A and it works as expected. If the condition already is met the app A would work as expected from the beginning. What is have tried so far My first attempt involved using an AppIntent and changing the openAppWhenRun programmatically based on the condition. I did however learn pretty quickly that changing the value of openAppWhenRun does not change if the AppIntent actually opens my app. The code for this looked like this where the value of openAppWhenRun is changed in another function. struct BlockerIntent: AppIntent { static let title: LocalizedStringResource = "Blocker App" static let description: LocalizedStringResource = "Blocks an app until condition is met" static var openAppWhenRun: Bool = false @MainActor func perform() async throws -> some IntentResult { return .result() } } Another attempt involved setting openAppWhenRun to false in an outer AppIntent and opening another inner AppIntent if the condition is met. If the condition in my app is met openAppWhenRun is set to true and instead of opening the inner AppIntent an Error is thrown. This functions as expected but there is an error notification showing every time I open the "blocked" app. struct BlockerIntent: AppIntent { static let title: LocalizedStringResource = "Blocker App" static let description: LocalizedStringResource = "Blocks an app until condition is met" static var openAppWhenRun: Bool = false func perform() async throws -> some IntentResult & OpensIntent { if (BlockerIntent.openAppWhenRun) { throw Error.notFound } return .result(opensIntent: OpenBlockerApp()) } enum Error: Swift.Error, CustomLocalizedStringResourceConvertible { case notFound var localizedStringResource: LocalizedStringResource { switch self { case .notFound: return "Ignore this message" } } } } struct OpenBlockerApp: AppIntent { static let title: LocalizedStringResource = "Open Blocker App" static let description: LocalizedStringResource = "Opens Blocker App" static var openAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult { return .result() } } My third attempt look similar to the previous one but instead I used two different inner AppIntents. The only difference between the two were that on had openAppWhenRun = false and the other had openAppWhenRun = true. struct BlockerIntent: AppIntent { static let title: LocalizedStringResource = "Blocker App" static let description: LocalizedStringResource = "Blacks an app until condition is met" static var openAppWhenRun: Bool = false func perform() async throws -> some IntentResult & OpensIntent { if (BlockerIntent.openAppWhenRun) { return .result(opensIntent: DoNotOpenBlockerApp()) } else { return .result(opensIntent: OpenBlockerApp()) } } } Trying this gives me this error: Function declares an opaque return type 'some IntentResult & OpensIntent', but the return statements in its body do not have matching underlying types I have also tried opening the app with a URL link with little to no success often ending up in an infinity loop, I did try the ForegroundContinuableIntent but it did not function as expected since it relies on the users input. Is there any way to do what I am trying to accomplish? I have seen other apps using a similar concept so I feel like this should be possible. Many thanks!
4
5
1k
Nov ’23
Returning a type from an Intent (basics)
Hello, I'm attempting to learn the basics of AppIntents. My test Hello World intent takes a number and doubles it. This page (https://developer.apple.com/documentation/appintents/providing-your-app-s-capabilities-to-system-services) seems to imply that you can return types from the perform() function. My code compiles, but crashes at runtime with the error perform() returned types not declared in method signature - Did not declare ReturnsValue but provided one Code: struct DoubleANumber: AppIntent { static var title: LocalizedStringResource = "Double a number" static var description = IntentDescription("Given a number, gives back twice that number.") @Parameter(title: "Start Number") var inputNumber: Double static var parameterSummary: some ParameterSummary { Summary("The number to double") } func perform() async throws -> some IntentResult & ReturnsValue { let outputNumber = inputNumber * 2 return .result(value: outputNumber) } } The value returned in the value property of the IntentResult is a Double. I would have assumed that this would be a valid primitive type (as mentioned in the earlier section of that docs page, covering parameters) and that the actual type returned is the wrapper .result type would be covered in the type in the method signature some IntentResult & ReturnsValue What am I missing? Thanks.
1
0
432
Nov ’23
Siri Not Speaking Disambiguation Introduction
I have a custom intent with multiple parameters. Two of the parameters are set up to handle disambiguation dialog. The intent definition file for each of these parameters is almost identical except for the parameter names and the wording in the siri dialog. Similarly, the code in the intent handler to resolve these parameters is nearly identical. But when disambiguation is invoked, the Disambiguation Introduction is only spoken by siri for one of the two parameters. What triggers the Disambiguation Introduction to be spoken in one and not the other? Here is the intentHandler code to resolve the first parameter (in which siri will speak the Disambiguation Introduction: - (void)resolvePartsListNameForAddPart:(AddPartIntent *)intent withCompletion:(void (^)(INStringResolutionResult *resolutionResult))completion NS_SWIFT_NAME(resolvePartsListName(for:with:)) API_AVAILABLE(ios(13.0), macos(10.16), watchos(6.0)) { ... NSMutableArray *options; options = [[NSMutableArray alloc] init]; NSString *anOption = [NSString stringWithFormat:@"Use '%@' ", intent.partsListName]; // option 1 [options addObject:anOption]; anOption = [NSString stringWithFormat:@"test1"]; // option 2 [options addObject:anOption]; ... anOption = [NSString stringWithFormat:@"test5"]; // option 6 [options addObject:anOption]; completion([INStringResolutionResult disambiguationWithStringsToDisambiguate:[options copy]]); return; ... } Here is the intentHandler code to resolve the second parameter (in which siri DOES NOT speak the Disambiguation Introduction: - (void)resolveChangeForAddPart:(AddPartIntent *)intent withCompletion:(void (^)(INStringResolutionResult *resolutionResult))completion NS_SWIFT_NAME(resolveChange(for:with:)) API_AVAILABLE(ios(13.0), macos(10.16), watchos(6.0)) { ... NSMutableArray *options; options = [[NSMutableArray alloc] init]; NSString *anOption = [NSString stringWithFormat:WOOD_TYPE_PARM]; // option 1 [options addObject:anOption]; // Option 2 anOption = [NSString stringWithFormat:PART_NAME_PARM]; [options addObject:anOption]; // Option 3 anOption = [NSString stringWithFormat:QUANTITY_PARM]; [options addObject:anOption]; // Option 4 anOption = [NSString stringWithFormat:DIMENSION_PARM]; [options addObject:anOption]; // Option 5 anOption = [NSString stringWithFormat:CANCEL_PARM]; [options addObject:anOption]; completion([INStringResolutionResult disambiguationWithStringsToDisambiguate:[options copy]]); return; } Here is the Intents definition for the working parameter where Siri speaks the Disambiguation Introduction: Here is the Intents definition for the non-working parameter Again, what triggers the Disambiguation Introduction to be spoken in one and not the other? FYI: it does not make any difference whether or not the Disambiguation Introduction has the parameters 'count' and 'change' (i.e. if I make the introduction be Hello World, it still doesn't get spoken).
0
0
368
Nov ’23