Share intents from within an app to drive system intelligence and show the app's actions in the Shortcuts app.

Posts under Intents tag

200 Posts

Post

Replies

Boosts

Views

Activity

CarPlay / Siri: single message display
We have an app with carplay-messaging capability, and have successfully integrated our app in order to read out the list of unread messages. However, if a single message arrives and our push notification appears, we are not able to have the Siri UI automatically read only that single message or announce it. The 'list' UI appears (siri: "would you like to read your messages...") when tapping the notification, whereas we would like the 'item' UI to appear immediately with the "reply, repeat, don't reply" buttons. Our intent handler service looks like this - basically the auto-generated one for a new Intent Handler Extension: import Intents // As an example, this class is set up to handle Message intents. // You will want to replace this or add other intents as appropriate. // The intents you wish to handle must be declared in the extension's Info.plist. // You can test your example integration by saying things to Siri like: // "Send a message using <myApp>" // "<myApp> John saying hello" // "Search for messages in <myApp>" class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling { override func handler(for intent: INIntent) -> Any { // This is the default implementation. If you want different objects to handle different intents, // you can override this and return the handler you want for that particular intent. return self } // MARK: - INSendMessageIntentHandling // Implement resolution methods to provide additional information about your intent (optional). func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) { if let recipients = intent.recipients { // If no recipients were provided we'll need to prompt for a value. if recipients.count == 0 { completion([INSendMessageRecipientResolutionResult.needsValue()]) return } var resolutionResults = [INSendMessageRecipientResolutionResult]() for recipient in recipients { let matchingContacts = [recipient] // Implement your contact matching logic here to create an array of matching contacts switch matchingContacts.count { case 2 ... Int.max: // We need Siri's help to ask user to pick one from the matches. resolutionResults += [INSendMessageRecipientResolutionResult.disambiguation(with: matchingContacts)] case 1: // We have exactly one matching contact resolutionResults += [INSendMessageRecipientResolutionResult.success(with: recipient)] case 0: // We have no contacts matching the description provided resolutionResults += [INSendMessageRecipientResolutionResult.unsupported()] default: break } } completion(resolutionResults) } else { completion([INSendMessageRecipientResolutionResult.needsValue()]) } } func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) { if let text = intent.content, !text.isEmpty { completion(INStringResolutionResult.success(with: text)) } else { completion(INStringResolutionResult.needsValue()) } } // Once resolution is completed, perform validation on the intent and provide confirmation (optional). func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { // Verify user is authenticated and your app is ready to send a message. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) let response = INSendMessageIntentResponse(code: .ready, userActivity: userActivity) completion(response) } // Handle the completed intent (required). func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { // Implement your application logic to send a message here. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity) completion(response) } // Implement handlers for each intent you wish to handle. As an example for messages, you may wish to also handle searchForMessages and setMessageAttributes. // MARK: - INSearchForMessagesIntentHandling func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) { // Implement your application logic to find a message that matches the information in the intent. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self)) let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity) // Initialize with found message's attributes response.messages = [INMessage( identifier: "identifier", conversationIdentifier: "convo1", content: "I am so excited about SiriKit!", dateSent: Date(), sender: INPerson(personHandle: INPersonHandle(value: "sarah@example.com", type: .emailAddress), nameComponents: nil, displayName: "Sarah", image: nil, contactIdentifier: nil, customIdentifier: nil), recipients: [INPerson(personHandle: INPersonHandle(value: "+1-415-555-5555", type: .phoneNumber), nameComponents: nil, displayName: "John", image: nil, contactIdentifier: nil, customIdentifier: nil)], messageType: .text )] completion(response) } // MARK: - INSetMessageAttributeIntentHandling func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) { // Implement your application logic to set the message attribute here. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self)) let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity) completion(response) } } Is there specific configuration required to allow display of a single message via tapping on the notification?
3
0
757
Sep ’24
Siri Intent Dismiss callback issue
I am opening the Siri shortcut screen from the viewDidLoad method, as follows: override func viewDidLoad() { super.viewDidLoad() // Present the Siri Shortcut screen to add Card Payment Intent let viewController = INUIAddVoiceShortcutViewController(shortcut: INShortcut(intent: self.cardPaymentIntent)!) viewController.modalPresentationStyle = .pageSheet // Setting Delegate viewController.delegate = self self.present(viewController, animated: true, completion: nil) } // Delegate Method Conformance :: INUIAddVoiceShortcutViewControllerDelegate @available(iOS 12.0, *) func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) { controller.dismiss(animated: true, completion: nil) // The issue is here. Whether we add the or Dismiss the Siri shortcut screen without adding it, this delegate gets called. } @available(iOS 12.0, *) func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) { controller.dismiss(animated: true, completion: nil) } // Card Payment Intent public var cardPaymentIntent: CardPaymentIntent { let intent = CardPaymentIntent() intent.suggestedInvocationPhrase = NSLocalizedString("Pay my credit card", comment: "") return intent } Whenever I present the siri shortcut screen, either I add the shortcut or dismiss the screen without adding. In both cases , the shortcut is added. And this method is called every time func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) Any solution ? while I dismiss the screen, i want it not to be added into the shortcut
1
0
831
Sep ’24
AppIntent @Dependency Throwing Error
I'm not really sure if I'm using the right lingo here because there's so little documentation on this, so apologies in advance. I have an app with a few custom intents that I'm attempting to transition to AppIntents. I have the newly transitioned intents showing up in the Shortcuts app as expected, however when I run them I get an immediate failure saying "The operation couldn't be completed" (see photo). Note that the "AppIntentsClient" class mentioned in the photo is the dependency I'm trying to import. I've narrowed it down to the @Dependency that I'm using in my intent handler. At the top of the intent handler I have a line: @Dependency private var appIntentsClient: any AppIntentsClient // NOTE: AppIntentsClient is a protocol -- could that be the issue? And if I comment out this line, the intent no longer throws that error. I'm following the guidelines shown in sample apps by setting the dependency on my main app's startup in didFinishLaunchingWithOptions like so: // gets called by the main app `didFinishLaunchingWithOptions` func onDidFinishLaunching() { let adapter = AppIntentsAdapter() //AppIntentsAdapter adheres to protocol AppIntentsClient self.appIntentsAdapter = adapter AppDependencyManager.shared.add(dependency: adapter) MyAppShortcuts.updateAppShortcutParameters() } Unfortunately there is virtually no documentation around AppDependencyManager or AppDependencies in general. Both documentation pages have at most one line, but don't indicate why this would be failing for me. Is there any information out there on why these errors may be happening? I've also looked at the Console app to see if the OS logs anything, but nothing of value was found. https://developer.apple.com/documentation/appintents/appdependencymanager https://developer.apple.com/documentation/appintents/appdependency
2
1
1.3k
Aug ’24
iOS18, interactive widget not respond (AppIntent not working)
here is my case: i add the AppIntent to both your app and widget extension targets. the intent will run my app process when app is running. it works perfectly on iOS 17. but iOS 18, my app process never called. i download app's demo, https://developer.apple.com/documentation/widgetkit/emoji-rangers-supporting-live-activities-interactivity-and-animations it looks like the same issue. it runs well because even it runs in the widget extension target, it still can present expected UI. but in real case, we need to run the app process to do some work. by debugging, i found the app process never called(set breakpoint). i add openAppWhenRun, it works well on iOS 18. but it will open the app when the widget is running. it is not what i want.
4
5
2.5k
Aug ’24
INPlayMediaIntent `mediaSearch` mediaName unreliable when searching for playlists
We are working with an app that uses the INPlayMediaIntent to allow users to select and play music using Siri. In building out this feature, we have noticed that when selecting playlists to play, Siri will consistently leave out information from the intent that we are use to resolve the media to play in the app. It seems that there is generally no rhyme or reason as to why some information is left out. Walking through a couple test cases, here is the phrase and corresponding mediaSearch that we receive when testing: "Hey Siri, play the playlist happy songs in the app " (this is a working example) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050780> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = happy songs; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist my favorites in the app " (this fails with a null mediaName) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050600> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = <null>; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist working out playlist in the app " (this fails as the term "playlist" is excluded) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050ae0> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = working out; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist recently added in the app " (this fails with a null mediaName) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x1140507e0> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = <null>; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } Based on the above, Siri seems to ignore playlists named "Recently Added", "My Favorites", and playlists that have the word "playlist" in them such as "Working Out Playlist". To rectify this, we attempted to set the INVocabulary for the playlist titles that a user has in the app, as suggested in this WWDC session: https://developer.apple.com/videos/play/wwdc2020/10060/ let vocabulary = INVocabulary.shared() vocabulary.setVocabularyStrings(NSOrderedSet(array: [ "my favorites", "recently added", "working out playlist" ]), of: .mediaPlaylistTitle); This seems to have no effect. We understand the note in https://developer.apple.com/documentation/sirikit/registering_custom_vocabulary_with_sirikit/ stating that "a few minutes" should be waited before testing custom vocabulary, but waiting upwards of 20 minutes and even restarting the device did not result in any of the custom vocabulary making a difference. If these playlist names are set in AppIntentVocabulary.plist, "Recently Added" and "My Favorites" are able to be discovered as playlists, but the other failed test cases remain failing. The obvious shortcoming here is that these are not dynamic. <key>ParameterVocabularies</key> <array> <dict> <key>ParameterNames</key> <array> <string>INPlayMediaIntent.playlistTitle</string> </array> <key>ParameterVocabulary</key> <array> <dict> <key>VocabularyItemIdentifier</key> <string>working out playlist</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>working out playlist</string> </dict> </array> </dict> <dict> <key>VocabularyItemIdentifier</key> <string>recently added</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>recently added</string> </dict> </array> </dict> <dict> <key>VocabularyItemIdentifier</key> <string>my favorites</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>my favourites</string> </dict> <dict> <key>VocabularyItemPhrase</key> <string>my favorites</string> </dict> </array> </dict> </array> </dict> </array> Given the above, our questions are as follows: Is there documentation surrounding how Siri may pass along the mediaSearch in INPlayMediaIntent and how/why information may be left out? Why does setting custom vocabulary with INVocabulary seem to have no effect, yet the same vocabulary in AppIntentVocabulary does have an effect? Is the functionality we are experiencing to be expected, or should this be reported as a bug? We've published the test app that we are using for debugging this functionality at this link: https://github.com/awojnowski/SiriTest
3
0
839
Aug ’24
EntityPropertyQuery with property from related entity
Hi, I am working on creating a EntityPropertyQuery for my App entity. I want the user to be able to use Shortcuts to search by a property in a related entity, but I'm struggling with how the syntax for that looks. I know the documentation for 'EntityPropertyQuery' suggests that this should be possible with a different initializer for the 'QueryProperty' that takes in a 'entityProvider' but I can't figure out how it works. For e.g. my CJPersonAppEntity has 'emails', which is of type CJEmailAppEntity, which has a property 'emailAddress'. I want the user to be able to find the 'person' by looking up an email address. When I try to provide this as a Property to filter by, inside CJPersonAppEntityQuery, but I get a syntax error: static var properties = QueryProperties { Property(\CJPersonEmailAppEntity.$emailAddress, entityProvider: { person in person.emails // error }) { EqualToComparator { NSPredicate(format: "emailAddress == %@", $0) } ContainsComparator { NSPredicate(format: "emailAddress CONTAINS %@", $0) } } } The error says "Cannot convert value of type '[CJPersonEmailAppEntity]' to closure result type 'CJPersonEmailAppEntity'" So it's not expecting an array, but an individual email item. But how do I provide that without running the predicate query that's specified in the closure? So I tried something like this , just returning something without worrying about correctness: Property(\CJPersonEmailAppEntity.$emailAddress, entityProvider: { person in person.emails.first ?? CJPersonEmailAppEntity() // satisfy compiler }) { EqualToComparator { NSPredicate(format: "emailAddress == %@", $0) } ContainsComparator { NSPredicate(format: "emailAddress CONTAINS %@", $0) } } and it built the app, but failed on another the step 'Extracting app intents metadata': error: Entity CJPersonAppEntity does not contain a property named emailAddress. Ensure that the property is wrapped with an @Property property wrapper So I'm not sure what the correct syntax for handling this case is, and I can't find any other examples of how it's done. Would love some feedback for this.
3
0
1.2k
Aug ’24
Why does my SwiftUI app crash when opened from an intent?
I'm encountering a crash in my SwiftUI app when it is opened via an AppIntent. The app runs perfectly when launched by tapping the app icon, but it crashes when opened from an intent. Here is a simplified version of my code: import AppIntents import SwiftData import SwiftUI @main struct GOGODemoApp: App { @State private var state: MyController = MyController() var body: some Scene { WindowGroup { MyView() //.environment(state) // ok } .environment(state) // failed to start app, crash with 'Dispatch queue: com.apple.main-thread' } } struct MyView: View { @Environment(MyController.self) var stateController var body: some View { Text("Hello") } } @Observable public class MyController { } struct OpenIntents: AppIntent { static var title: LocalizedStringResource = "OpenIntents" static var description = IntentDescription("Open App from intents.") static var openAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult { return .result() } } Observations: The app works fine when launched by tapping the app icon. The app crashes when opened via an AppIntent. The app works if I inject the environment in MyView instead of in WindowGroup. Question: Why does injecting the environment in WindowGroup cause the app to crash when opened from an intent, but works fine otherwise? What is the difference when injecting the environment directly in MyView?
1
0
748
Aug ’24
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!
6
5
2.3k
Aug ’24
Share / Action Extension Not Shown and corrupts Share dialog for all system
1 I have just added a share extension with an audio predicate, but in the "Files" app, my app doesn’t appear in the "Share" menu for audio files. The Share Activity View Controller does not show my app. There seems to be no way to make it work. I have already spent 2 days googling this and searching forums. Some users say this is an iOS bug, while others suggest restarting the device. Nothing helps. Just build and run the ShareExtension using the Files app. Try sharing any file and note that my app does not appear in the share list options. I am using the latest iOS 17.5 release version. 2 After starting to implement the sharing feature in my app Anywhere Offline Music Player, I noticed that my phone/iPad freezes when any share dialog from any place in the system is being shown. Additionally, all other apps are missing from the share list. When I try to share a file from any app, the share dialog first appears as a shadow, then glitches, and finally shows up, but the Files app option is missing, so I can't save the shared file. This issue persists even after removing my app, and only a reboot helps. Other users report this happening regardless of whether my app is installed or not. Sometimes it works without any lags, but mostly it does not. I have no idea what this depends on. The same issue occurs on iPads using the latest beta versions. Removing my app and rebooting the device temporarily "fixes" this.
1
0
1k
Aug ’24
Unable to observe Focus status changes from an Intents app extension
I am writing a communication app that relies on the INShareFocusStatusIntentHandling protocol. However, it appears this API is not functional, even with the proper permissions and entitlements. Given the example code here, I am unable to trigger the logs in the INShareFocusStatusIntentHandling extension. In this code, when enabling or disabling focus, line 33 of IntentHandler.swift never gets logged, even though FocusStatusCenter is authorized for parent app, UserNotifications authorized for parent app (target), and Communication Notifications entitlement has been added to the parent app. I am also unable to hit any breakpoints in the extension. It seems as if the extension is simply never triggered -- maybe even broken at the OS-level. I have tried both iOS 17 and the latest 18 beta. Other users have reported similar difficulties in these forums. To replicate, Install the example app. Give the app UserNotifications and FocusStatus permissions. Background the app. Change focus status. Check console. Notice that the extension handler is never triggered/logged.
1
0
976
Jul ’24
How to extend my exist Toggle with intents
I create a toggle component based on Toggle public struct Checkbox: View { ... public init(...) { ... } public var body: some View { return HStack(spacing: 8) { ZStack { Toggle("", isOn: $isPrivateOn) ... } ... } } } how can I create a init method to support init with AppIntent like: // Available when SwiftUI is imported with AppIntents @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) extension Toggle { /// Creates a toggle performing an `AppIntent`. /// /// - Parameters: /// - isOn: Whether the toggle is on or off. /// - intent: The `AppIntent` to be performed. /// - label: A view that describes the purpose of the toggle. public init<I>(isOn: Bool, intent: I, @ViewBuilder label: () -> Label) where I : AppIntent }
1
0
786
Jul ’24
Error generating files in compilation cause AppEntity and Widget Extension on iOS17
When I add AppEnity to my model, I receive this error that is still repeated for each attribute in the model. The models are already marked for Widget Extension in Target Membership. I have already cleaned and restarted, nothing works. Will anyone know what I'm doing wrong? Unable to find matching source file for path "@_swiftmacro_21HabitWidgetsExtension0A05ModelfMm.swift" import SwiftData import AppIntents enum FrecuenciaCumplimiento: String, Codable { case diario case semanal case mensual } @Model final class Habit: AppEntity { @Attribute(.unique) var id: UUID var nombre: String var descripcion: String var icono: String var color: String var esHabitoPositivo: Bool var valorObjetivo: Double var unidadObjetivo: String var frecuenciaCumplimiento: FrecuenciaCumplimiento static var typeDisplayRepresentation: TypeDisplayRepresentation = "Hábito" static var defaultQuery = HabitQuery() var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(nombre)") } static var allHabits: [Habit] = [ Habit(id: UUID(), nombre: "uno", descripcion: "", icono: "circle", color: "#BF0000", esHabitoPositivo: true, valorObjetivo: 1.0, unidadObjetivo: "", frecuenciaCumplimiento: .mensual), Habit(id: UUID(), nombre: "dos", descripcion: "", icono: "circle", color: "#BF0000", esHabitoPositivo: true, valorObjetivo: 1.0, unidadObjetivo: "", frecuenciaCumplimiento: .mensual) ] /* static func loadAllHabits() async throws { do { let modelContainer = try ModelContainer(for: Habit.self) let descriptor = FetchDescriptor<Habit>() allHabits = try await modelContainer.mainContext.fetch(descriptor) } catch { // Manejo de errores si es necesario print("Error al cargar hábitos: \(error)") throw error } } */ init(id: UUID = UUID(), nombre: String, descripcion: String, icono: String, color: String, esHabitoPositivo: Bool, valorObjetivo: Double, unidadObjetivo: String, frecuenciaCumplimiento: FrecuenciaCumplimiento) { self.id = id self.nombre = nombre self.descripcion = descripcion self.icono = icono self.color = color self.esHabitoPositivo = esHabitoPositivo self.valorObjetivo = valorObjetivo self.unidadObjetivo = unidadObjetivo self.frecuenciaCumplimiento = frecuenciaCumplimiento } @Relationship(deleteRule: .cascade) var habitRecords: [HabitRecord] = [] } struct HabitQuery: EntityQuery { func entities(for identifiers: [Habit.ID]) async throws -> [Habit] { //try await Habit.loadAllHabits() return Habit.allHabits.filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [Habit] { //try await Habit.loadAllHabits() return Habit.allHabits// .filter { $0.isAvailable } } func defaultResult() async -> Habit? { try? await suggestedEntities().first } }
3
2
926
Jul ’24
Type '' does not conform to protocol '_IntentValue' - AppIntents
Hi there. First time poster! I'm attempting to implement App Intents in my app, as part of the App Intent I have included a parameter requiring the user specify one of their 'to do lists'. @Parameter(title: "List", description: "One of your Marvelist lists.") var list: MarvelistModels.List However, I'm receiving the below error in Xcode... Type 'MarvelistModels.List' does not conform to protocol '_IntentValue' When I go to the struct for MarvelistModels.List, and attempt to make it conform to _IntentValue, it adds typealias Specification = type to my struct... however, I can't quite figure out how to make it conform. Any help/advice would be greatly appreicated!
1
1
1.2k
Jul ’24
Chaining app intents in code
I would like to split up my intents into smaller intents with more atomic pieces of functionality that I can then call one intent from another. For example: struct SumValuesIntent: AppIntent { static var title: LocalizedStringResource { "Sum Values" } let a: Int let b: Int init(a: Int, b: Int) { self.a = a self.b = b } init() { self.init(a: 0, b: 0) } func perform() async throws -> some IntentResult { let sum = a + b print("SumValuesIntent:", sum) return .result(value: sum) } } struct PrintValueIntent: AppIntent { static var title: LocalizedStringResource { "Print Value" } let string: String init(string: String) { self.string = string } init() { self.init(string: "") } func perform() async throws -> some IntentResult { print("PrintValueIntent:", string) return .result() } } What is the best way to chain intents like these? I tried .result(opensIntent: PrintValueIntent(string: String(describing: sum))) as the return type of SumValuesIntent.perform but that doesn't seem to work. Then I tried try await PrintValueIntent(string: String(describing: sum)).perform() as the return type and that works but I'm not sure that's the correct way to do it.
0
1
890
Jul ’24
App Intents "Text" parameters seem broken in iOS 17.6 beta
I'm getting widespread reports from users trialling iOS 17.6 public beta that Siri Shortcuts are failing whenever they enter any text that looks like a URL. It's getting reported to me because my app happens to have an app intent with a string parameter which can contain a URL in some circumstances. However it's easily reproducible outside of my app: just create a 2 line shortcut like the one below. If you change "This is some text" to "https://www.apple.com" the shortcut below will fail: In iOS 17.5 entering "https://www.apple.com" works fine. I've raised feedback on this (FB14206088) but can anyone confirm that this is indeed a bug and not some weird new feature of Shortcuts where the contents of a variable can somehow change the type of a variable? It would be very, very bad if this were so.
1
0
940
Jul ’24
Updating Automation Intervals
It would greatly benefit the entire community if there was a "Once" button under the "automation" section that is apart of "shortcuts" app. Currently there are 3 selections - Daily, Weekly, Monthly. Please add a 4th selection - "Once" I'm asking because I was told that I could do this here. Thanks for anyone that supports this as I feel it would benefit us immensely.
1
0
646
Jul ’24
CarPlay / Siri: single message display
We have an app with carplay-messaging capability, and have successfully integrated our app in order to read out the list of unread messages. However, if a single message arrives and our push notification appears, we are not able to have the Siri UI automatically read only that single message or announce it. The 'list' UI appears (siri: "would you like to read your messages...") when tapping the notification, whereas we would like the 'item' UI to appear immediately with the "reply, repeat, don't reply" buttons. Our intent handler service looks like this - basically the auto-generated one for a new Intent Handler Extension: import Intents // As an example, this class is set up to handle Message intents. // You will want to replace this or add other intents as appropriate. // The intents you wish to handle must be declared in the extension's Info.plist. // You can test your example integration by saying things to Siri like: // "Send a message using <myApp>" // "<myApp> John saying hello" // "Search for messages in <myApp>" class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling { override func handler(for intent: INIntent) -> Any { // This is the default implementation. If you want different objects to handle different intents, // you can override this and return the handler you want for that particular intent. return self } // MARK: - INSendMessageIntentHandling // Implement resolution methods to provide additional information about your intent (optional). func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) { if let recipients = intent.recipients { // If no recipients were provided we'll need to prompt for a value. if recipients.count == 0 { completion([INSendMessageRecipientResolutionResult.needsValue()]) return } var resolutionResults = [INSendMessageRecipientResolutionResult]() for recipient in recipients { let matchingContacts = [recipient] // Implement your contact matching logic here to create an array of matching contacts switch matchingContacts.count { case 2 ... Int.max: // We need Siri's help to ask user to pick one from the matches. resolutionResults += [INSendMessageRecipientResolutionResult.disambiguation(with: matchingContacts)] case 1: // We have exactly one matching contact resolutionResults += [INSendMessageRecipientResolutionResult.success(with: recipient)] case 0: // We have no contacts matching the description provided resolutionResults += [INSendMessageRecipientResolutionResult.unsupported()] default: break } } completion(resolutionResults) } else { completion([INSendMessageRecipientResolutionResult.needsValue()]) } } func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) { if let text = intent.content, !text.isEmpty { completion(INStringResolutionResult.success(with: text)) } else { completion(INStringResolutionResult.needsValue()) } } // Once resolution is completed, perform validation on the intent and provide confirmation (optional). func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { // Verify user is authenticated and your app is ready to send a message. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) let response = INSendMessageIntentResponse(code: .ready, userActivity: userActivity) completion(response) } // Handle the completed intent (required). func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { // Implement your application logic to send a message here. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity) completion(response) } // Implement handlers for each intent you wish to handle. As an example for messages, you may wish to also handle searchForMessages and setMessageAttributes. // MARK: - INSearchForMessagesIntentHandling func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) { // Implement your application logic to find a message that matches the information in the intent. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self)) let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity) // Initialize with found message's attributes response.messages = [INMessage( identifier: "identifier", conversationIdentifier: "convo1", content: "I am so excited about SiriKit!", dateSent: Date(), sender: INPerson(personHandle: INPersonHandle(value: "sarah@example.com", type: .emailAddress), nameComponents: nil, displayName: "Sarah", image: nil, contactIdentifier: nil, customIdentifier: nil), recipients: [INPerson(personHandle: INPersonHandle(value: "+1-415-555-5555", type: .phoneNumber), nameComponents: nil, displayName: "John", image: nil, contactIdentifier: nil, customIdentifier: nil)], messageType: .text )] completion(response) } // MARK: - INSetMessageAttributeIntentHandling func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) { // Implement your application logic to set the message attribute here. let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self)) let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity) completion(response) } } Is there specific configuration required to allow display of a single message via tapping on the notification?
Replies
3
Boosts
0
Views
757
Activity
Sep ’24
Async Image is not loading the image in App Intent result's view
Async image is not loading in app intent's view. Image is just not loading without any error
Replies
1
Boosts
0
Views
557
Activity
Sep ’24
Siri Intent Dismiss callback issue
I am opening the Siri shortcut screen from the viewDidLoad method, as follows: override func viewDidLoad() { super.viewDidLoad() // Present the Siri Shortcut screen to add Card Payment Intent let viewController = INUIAddVoiceShortcutViewController(shortcut: INShortcut(intent: self.cardPaymentIntent)!) viewController.modalPresentationStyle = .pageSheet // Setting Delegate viewController.delegate = self self.present(viewController, animated: true, completion: nil) } // Delegate Method Conformance :: INUIAddVoiceShortcutViewControllerDelegate @available(iOS 12.0, *) func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) { controller.dismiss(animated: true, completion: nil) // The issue is here. Whether we add the or Dismiss the Siri shortcut screen without adding it, this delegate gets called. } @available(iOS 12.0, *) func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) { controller.dismiss(animated: true, completion: nil) } // Card Payment Intent public var cardPaymentIntent: CardPaymentIntent { let intent = CardPaymentIntent() intent.suggestedInvocationPhrase = NSLocalizedString("Pay my credit card", comment: "") return intent } Whenever I present the siri shortcut screen, either I add the shortcut or dismiss the screen without adding. In both cases , the shortcut is added. And this method is called every time func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) Any solution ? while I dismiss the screen, i want it not to be added into the shortcut
Replies
1
Boosts
0
Views
831
Activity
Sep ’24
AppIntent @Dependency Throwing Error
I'm not really sure if I'm using the right lingo here because there's so little documentation on this, so apologies in advance. I have an app with a few custom intents that I'm attempting to transition to AppIntents. I have the newly transitioned intents showing up in the Shortcuts app as expected, however when I run them I get an immediate failure saying "The operation couldn't be completed" (see photo). Note that the "AppIntentsClient" class mentioned in the photo is the dependency I'm trying to import. I've narrowed it down to the @Dependency that I'm using in my intent handler. At the top of the intent handler I have a line: @Dependency private var appIntentsClient: any AppIntentsClient // NOTE: AppIntentsClient is a protocol -- could that be the issue? And if I comment out this line, the intent no longer throws that error. I'm following the guidelines shown in sample apps by setting the dependency on my main app's startup in didFinishLaunchingWithOptions like so: // gets called by the main app `didFinishLaunchingWithOptions` func onDidFinishLaunching() { let adapter = AppIntentsAdapter() //AppIntentsAdapter adheres to protocol AppIntentsClient self.appIntentsAdapter = adapter AppDependencyManager.shared.add(dependency: adapter) MyAppShortcuts.updateAppShortcutParameters() } Unfortunately there is virtually no documentation around AppDependencyManager or AppDependencies in general. Both documentation pages have at most one line, but don't indicate why this would be failing for me. Is there any information out there on why these errors may be happening? I've also looked at the Console app to see if the OS logs anything, but nothing of value was found. https://developer.apple.com/documentation/appintents/appdependencymanager https://developer.apple.com/documentation/appintents/appdependency
Replies
2
Boosts
1
Views
1.3k
Activity
Aug ’24
iOS18, interactive widget not respond (AppIntent not working)
here is my case: i add the AppIntent to both your app and widget extension targets. the intent will run my app process when app is running. it works perfectly on iOS 17. but iOS 18, my app process never called. i download app's demo, https://developer.apple.com/documentation/widgetkit/emoji-rangers-supporting-live-activities-interactivity-and-animations it looks like the same issue. it runs well because even it runs in the widget extension target, it still can present expected UI. but in real case, we need to run the app process to do some work. by debugging, i found the app process never called(set breakpoint). i add openAppWhenRun, it works well on iOS 18. but it will open the app when the widget is running. it is not what i want.
Replies
4
Boosts
5
Views
2.5k
Activity
Aug ’24
INPlayMediaIntent `mediaSearch` mediaName unreliable when searching for playlists
We are working with an app that uses the INPlayMediaIntent to allow users to select and play music using Siri. In building out this feature, we have noticed that when selecting playlists to play, Siri will consistently leave out information from the intent that we are use to resolve the media to play in the app. It seems that there is generally no rhyme or reason as to why some information is left out. Walking through a couple test cases, here is the phrase and corresponding mediaSearch that we receive when testing: "Hey Siri, play the playlist happy songs in the app " (this is a working example) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050780> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = happy songs; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist my favorites in the app " (this fails with a null mediaName) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050600> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = <null>; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist working out playlist in the app " (this fails as the term "playlist" is excluded) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x114050ae0> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = working out; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } "Hey Siri, play the playlist recently added in the app " (this fails with a null mediaName) ▿ Optional<INMediaSearch> - some : <INMediaSearch: 0x1140507e0> { reference = 0; mediaType = 5; sortOrder = 0; albumName = <null>; mediaName = <null>; genreNames = ( ); artistName = <null>; moodNames = ( ); releaseDate = <null>; mediaIdentifier = <null>; } Based on the above, Siri seems to ignore playlists named "Recently Added", "My Favorites", and playlists that have the word "playlist" in them such as "Working Out Playlist". To rectify this, we attempted to set the INVocabulary for the playlist titles that a user has in the app, as suggested in this WWDC session: https://developer.apple.com/videos/play/wwdc2020/10060/ let vocabulary = INVocabulary.shared() vocabulary.setVocabularyStrings(NSOrderedSet(array: [ "my favorites", "recently added", "working out playlist" ]), of: .mediaPlaylistTitle); This seems to have no effect. We understand the note in https://developer.apple.com/documentation/sirikit/registering_custom_vocabulary_with_sirikit/ stating that "a few minutes" should be waited before testing custom vocabulary, but waiting upwards of 20 minutes and even restarting the device did not result in any of the custom vocabulary making a difference. If these playlist names are set in AppIntentVocabulary.plist, "Recently Added" and "My Favorites" are able to be discovered as playlists, but the other failed test cases remain failing. The obvious shortcoming here is that these are not dynamic. <key>ParameterVocabularies</key> <array> <dict> <key>ParameterNames</key> <array> <string>INPlayMediaIntent.playlistTitle</string> </array> <key>ParameterVocabulary</key> <array> <dict> <key>VocabularyItemIdentifier</key> <string>working out playlist</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>working out playlist</string> </dict> </array> </dict> <dict> <key>VocabularyItemIdentifier</key> <string>recently added</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>recently added</string> </dict> </array> </dict> <dict> <key>VocabularyItemIdentifier</key> <string>my favorites</string> <key>VocabularyItemSynonyms</key> <array> <dict> <key>VocabularyItemPhrase</key> <string>my favourites</string> </dict> <dict> <key>VocabularyItemPhrase</key> <string>my favorites</string> </dict> </array> </dict> </array> </dict> </array> Given the above, our questions are as follows: Is there documentation surrounding how Siri may pass along the mediaSearch in INPlayMediaIntent and how/why information may be left out? Why does setting custom vocabulary with INVocabulary seem to have no effect, yet the same vocabulary in AppIntentVocabulary does have an effect? Is the functionality we are experiencing to be expected, or should this be reported as a bug? We've published the test app that we are using for debugging this functionality at this link: https://github.com/awojnowski/SiriTest
Replies
3
Boosts
0
Views
839
Activity
Aug ’24
Getting the error occur while running your shortcut
The action “bla bla” could not run because of an internal error on specific mobile only I have tried updating shortcuts app and restart my phone but nothing works
Replies
1
Boosts
0
Views
670
Activity
Aug ’24
EntityPropertyQuery with property from related entity
Hi, I am working on creating a EntityPropertyQuery for my App entity. I want the user to be able to use Shortcuts to search by a property in a related entity, but I'm struggling with how the syntax for that looks. I know the documentation for 'EntityPropertyQuery' suggests that this should be possible with a different initializer for the 'QueryProperty' that takes in a 'entityProvider' but I can't figure out how it works. For e.g. my CJPersonAppEntity has 'emails', which is of type CJEmailAppEntity, which has a property 'emailAddress'. I want the user to be able to find the 'person' by looking up an email address. When I try to provide this as a Property to filter by, inside CJPersonAppEntityQuery, but I get a syntax error: static var properties = QueryProperties { Property(\CJPersonEmailAppEntity.$emailAddress, entityProvider: { person in person.emails // error }) { EqualToComparator { NSPredicate(format: "emailAddress == %@", $0) } ContainsComparator { NSPredicate(format: "emailAddress CONTAINS %@", $0) } } } The error says "Cannot convert value of type '[CJPersonEmailAppEntity]' to closure result type 'CJPersonEmailAppEntity'" So it's not expecting an array, but an individual email item. But how do I provide that without running the predicate query that's specified in the closure? So I tried something like this , just returning something without worrying about correctness: Property(\CJPersonEmailAppEntity.$emailAddress, entityProvider: { person in person.emails.first ?? CJPersonEmailAppEntity() // satisfy compiler }) { EqualToComparator { NSPredicate(format: "emailAddress == %@", $0) } ContainsComparator { NSPredicate(format: "emailAddress CONTAINS %@", $0) } } and it built the app, but failed on another the step 'Extracting app intents metadata': error: Entity CJPersonAppEntity does not contain a property named emailAddress. Ensure that the property is wrapped with an @Property property wrapper So I'm not sure what the correct syntax for handling this case is, and I can't find any other examples of how it's done. Would love some feedback for this.
Replies
3
Boosts
0
Views
1.2k
Activity
Aug ’24
Why does my SwiftUI app crash when opened from an intent?
I'm encountering a crash in my SwiftUI app when it is opened via an AppIntent. The app runs perfectly when launched by tapping the app icon, but it crashes when opened from an intent. Here is a simplified version of my code: import AppIntents import SwiftData import SwiftUI @main struct GOGODemoApp: App { @State private var state: MyController = MyController() var body: some Scene { WindowGroup { MyView() //.environment(state) // ok } .environment(state) // failed to start app, crash with 'Dispatch queue: com.apple.main-thread' } } struct MyView: View { @Environment(MyController.self) var stateController var body: some View { Text("Hello") } } @Observable public class MyController { } struct OpenIntents: AppIntent { static var title: LocalizedStringResource = "OpenIntents" static var description = IntentDescription("Open App from intents.") static var openAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult { return .result() } } Observations: The app works fine when launched by tapping the app icon. The app crashes when opened via an AppIntent. The app works if I inject the environment in MyView instead of in WindowGroup. Question: Why does injecting the environment in WindowGroup cause the app to crash when opened from an intent, but works fine otherwise? What is the difference when injecting the environment directly in MyView?
Replies
1
Boosts
0
Views
748
Activity
Aug ’24
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!
Replies
6
Boosts
5
Views
2.3k
Activity
Aug ’24
Share / Action Extension Not Shown and corrupts Share dialog for all system
1 I have just added a share extension with an audio predicate, but in the "Files" app, my app doesn’t appear in the "Share" menu for audio files. The Share Activity View Controller does not show my app. There seems to be no way to make it work. I have already spent 2 days googling this and searching forums. Some users say this is an iOS bug, while others suggest restarting the device. Nothing helps. Just build and run the ShareExtension using the Files app. Try sharing any file and note that my app does not appear in the share list options. I am using the latest iOS 17.5 release version. 2 After starting to implement the sharing feature in my app Anywhere Offline Music Player, I noticed that my phone/iPad freezes when any share dialog from any place in the system is being shown. Additionally, all other apps are missing from the share list. When I try to share a file from any app, the share dialog first appears as a shadow, then glitches, and finally shows up, but the Files app option is missing, so I can't save the shared file. This issue persists even after removing my app, and only a reboot helps. Other users report this happening regardless of whether my app is installed or not. Sometimes it works without any lags, but mostly it does not. I have no idea what this depends on. The same issue occurs on iPads using the latest beta versions. Removing my app and rebooting the device temporarily "fixes" this.
Replies
1
Boosts
0
Views
1k
Activity
Aug ’24
Unable to observe Focus status changes from an Intents app extension
I am writing a communication app that relies on the INShareFocusStatusIntentHandling protocol. However, it appears this API is not functional, even with the proper permissions and entitlements. Given the example code here, I am unable to trigger the logs in the INShareFocusStatusIntentHandling extension. In this code, when enabling or disabling focus, line 33 of IntentHandler.swift never gets logged, even though FocusStatusCenter is authorized for parent app, UserNotifications authorized for parent app (target), and Communication Notifications entitlement has been added to the parent app. I am also unable to hit any breakpoints in the extension. It seems as if the extension is simply never triggered -- maybe even broken at the OS-level. I have tried both iOS 17 and the latest 18 beta. Other users have reported similar difficulties in these forums. To replicate, Install the example app. Give the app UserNotifications and FocusStatus permissions. Background the app. Change focus status. Check console. Notice that the extension handler is never triggered/logged.
Replies
1
Boosts
0
Views
976
Activity
Jul ’24
How to extend my exist Toggle with intents
I create a toggle component based on Toggle public struct Checkbox: View { ... public init(...) { ... } public var body: some View { return HStack(spacing: 8) { ZStack { Toggle("", isOn: $isPrivateOn) ... } ... } } } how can I create a init method to support init with AppIntent like: // Available when SwiftUI is imported with AppIntents @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) extension Toggle { /// Creates a toggle performing an `AppIntent`. /// /// - Parameters: /// - isOn: Whether the toggle is on or off. /// - intent: The `AppIntent` to be performed. /// - label: A view that describes the purpose of the toggle. public init<I>(isOn: Bool, intent: I, @ViewBuilder label: () -> Label) where I : AppIntent }
Replies
1
Boosts
0
Views
786
Activity
Jul ’24
Error generating files in compilation cause AppEntity and Widget Extension on iOS17
When I add AppEnity to my model, I receive this error that is still repeated for each attribute in the model. The models are already marked for Widget Extension in Target Membership. I have already cleaned and restarted, nothing works. Will anyone know what I'm doing wrong? Unable to find matching source file for path "@_swiftmacro_21HabitWidgetsExtension0A05ModelfMm.swift" import SwiftData import AppIntents enum FrecuenciaCumplimiento: String, Codable { case diario case semanal case mensual } @Model final class Habit: AppEntity { @Attribute(.unique) var id: UUID var nombre: String var descripcion: String var icono: String var color: String var esHabitoPositivo: Bool var valorObjetivo: Double var unidadObjetivo: String var frecuenciaCumplimiento: FrecuenciaCumplimiento static var typeDisplayRepresentation: TypeDisplayRepresentation = "Hábito" static var defaultQuery = HabitQuery() var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(nombre)") } static var allHabits: [Habit] = [ Habit(id: UUID(), nombre: "uno", descripcion: "", icono: "circle", color: "#BF0000", esHabitoPositivo: true, valorObjetivo: 1.0, unidadObjetivo: "", frecuenciaCumplimiento: .mensual), Habit(id: UUID(), nombre: "dos", descripcion: "", icono: "circle", color: "#BF0000", esHabitoPositivo: true, valorObjetivo: 1.0, unidadObjetivo: "", frecuenciaCumplimiento: .mensual) ] /* static func loadAllHabits() async throws { do { let modelContainer = try ModelContainer(for: Habit.self) let descriptor = FetchDescriptor<Habit>() allHabits = try await modelContainer.mainContext.fetch(descriptor) } catch { // Manejo de errores si es necesario print("Error al cargar hábitos: \(error)") throw error } } */ init(id: UUID = UUID(), nombre: String, descripcion: String, icono: String, color: String, esHabitoPositivo: Bool, valorObjetivo: Double, unidadObjetivo: String, frecuenciaCumplimiento: FrecuenciaCumplimiento) { self.id = id self.nombre = nombre self.descripcion = descripcion self.icono = icono self.color = color self.esHabitoPositivo = esHabitoPositivo self.valorObjetivo = valorObjetivo self.unidadObjetivo = unidadObjetivo self.frecuenciaCumplimiento = frecuenciaCumplimiento } @Relationship(deleteRule: .cascade) var habitRecords: [HabitRecord] = [] } struct HabitQuery: EntityQuery { func entities(for identifiers: [Habit.ID]) async throws -> [Habit] { //try await Habit.loadAllHabits() return Habit.allHabits.filter { identifiers.contains($0.id) } } func suggestedEntities() async throws -> [Habit] { //try await Habit.loadAllHabits() return Habit.allHabits// .filter { $0.isAvailable } } func defaultResult() async -> Habit? { try? await suggestedEntities().first } }
Replies
3
Boosts
2
Views
926
Activity
Jul ’24
Type '' does not conform to protocol '_IntentValue' - AppIntents
Hi there. First time poster! I'm attempting to implement App Intents in my app, as part of the App Intent I have included a parameter requiring the user specify one of their 'to do lists'. @Parameter(title: "List", description: "One of your Marvelist lists.") var list: MarvelistModels.List However, I'm receiving the below error in Xcode... Type 'MarvelistModels.List' does not conform to protocol '_IntentValue' When I go to the struct for MarvelistModels.List, and attempt to make it conform to _IntentValue, it adds typealias Specification = type to my struct... however, I can't quite figure out how to make it conform. Any help/advice would be greatly appreicated!
Replies
1
Boosts
1
Views
1.2k
Activity
Jul ’24
Chaining app intents in code
I would like to split up my intents into smaller intents with more atomic pieces of functionality that I can then call one intent from another. For example: struct SumValuesIntent: AppIntent { static var title: LocalizedStringResource { "Sum Values" } let a: Int let b: Int init(a: Int, b: Int) { self.a = a self.b = b } init() { self.init(a: 0, b: 0) } func perform() async throws -> some IntentResult { let sum = a + b print("SumValuesIntent:", sum) return .result(value: sum) } } struct PrintValueIntent: AppIntent { static var title: LocalizedStringResource { "Print Value" } let string: String init(string: String) { self.string = string } init() { self.init(string: "") } func perform() async throws -> some IntentResult { print("PrintValueIntent:", string) return .result() } } What is the best way to chain intents like these? I tried .result(opensIntent: PrintValueIntent(string: String(describing: sum))) as the return type of SumValuesIntent.perform but that doesn't seem to work. Then I tried try await PrintValueIntent(string: String(describing: sum)).perform() as the return type and that works but I'm not sure that's the correct way to do it.
Replies
0
Boosts
1
Views
890
Activity
Jul ’24
App Intents "Text" parameters seem broken in iOS 17.6 beta
I'm getting widespread reports from users trialling iOS 17.6 public beta that Siri Shortcuts are failing whenever they enter any text that looks like a URL. It's getting reported to me because my app happens to have an app intent with a string parameter which can contain a URL in some circumstances. However it's easily reproducible outside of my app: just create a 2 line shortcut like the one below. If you change "This is some text" to "https://www.apple.com" the shortcut below will fail: In iOS 17.5 entering "https://www.apple.com" works fine. I've raised feedback on this (FB14206088) but can anyone confirm that this is indeed a bug and not some weird new feature of Shortcuts where the contents of a variable can somehow change the type of a variable? It would be very, very bad if this were so.
Replies
1
Boosts
0
Views
940
Activity
Jul ’24
Can Objective-C Framework Implement AppIntent
I want to implement AppIntent in my Objective-C framework, because we need to design a fast pass to certain function. However, I create a struct inherited from AppIntent, and create a projectName-Bridging-Header.h in my framework just like I did in my project. It seems like framework don't work, I can't find it in shortcuts
Replies
1
Boosts
0
Views
926
Activity
Jul ’24
Updating Automation Intervals
It would greatly benefit the entire community if there was a "Once" button under the "automation" section that is apart of "shortcuts" app. Currently there are 3 selections - Daily, Weekly, Monthly. Please add a 4th selection - "Once" I'm asking because I was told that I could do this here. Thanks for anyone that supports this as I feel it would benefit us immensely.
Replies
1
Boosts
0
Views
646
Activity
Jul ’24
Wallet Extension Error
While Implementing Wallet Intent Extension, and after verification The only message i get is Cannot Add Card There are no available cards to add. Any help here is appreciated.
Replies
1
Boosts
0
Views
998
Activity
Jun ’24