Siri触发AppIntent时IntentCurrencyAmount参数循环询问问题
Siri调用AppIntent时IntentCurrencyAmount参数循环询问无法识别的问题解决
问题重现
在SwiftUI iOS应用中,通过Siri调用带IntentCurrencyAmount参数的AppIntent发起交易时,Siri会反复询问金额参数,且无法识别用户的语音回答,perform方法完全不会执行。但通过快捷指令的图形界面触发时,参数可以正常输入,功能完全正常。
已尝试的无效方案:
- 尝试给参数设置默认值,但
IntentCurrencyParameter不支持此操作 - 固定货币为单一值"EUR"简化逻辑,无效
- 添加
needValueRequest,但因perform方法未触发而不起作用
核心原因
- 快捷指令短语未关联参数:当前的
AppShortcut短语没有包含参数占位符,Siri无法识别指令中需要捕获金额参数,导致进入无限询问循环。 - Siri语音解析缺少明确指引:没有为参数提供自定义解析逻辑,当用户用自然语言回答时,Siri无法正确映射为
IntentCurrencyAmount类型。
解决方案
1. 更新AppShortcut短语,添加参数占位符
修改快捷指令的触发短语,加入参数占位符,让Siri知道可以在指令中直接接收金额输入,同时支持后续询问时的解析:
struct TapAutoShortcuts : AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: OpenTransaction(), phrases: [ "Lancer une transaction [de \(\.$amount)] avec \(.applicationName)", "Déclencher une transaction [de \(\.$amount)] via \(.applicationName)" ], shortTitle: "Lancer une transaction", systemImageName: "gear" ) } }
2. 添加参数解析方法,手动处理Siri输入
实现参数的resolve(for:)方法,帮助Siri将用户的语音回答转换为合法的IntentCurrencyAmount:
@Parameter(title: "Montant", currencyCodes: ["EUR"], inclusiveRange: (lowerBound: 0.01, upperBound: 100000000), requestValueDialog: IntentDialog("Une transaction de quel montant ?") ) var amount: IntentCurrencyAmount // 添加参数解析方法 func resolveAmount(for intentParameter: IntentParameter, with completion: @escaping (IntentCurrencyAmount?) -> Void) { guard let userInput = intentParameter.value as? String else { completion(nil) return } let numberFormatter = NumberFormatter() numberFormatter.locale = Locale(identifier: "fr_FR") numberFormatter.numberStyle = .decimal if let number = numberFormatter.number(from: userInput) { let currencyAmount = IntentCurrencyAmount(amount: NSDecimalNumber(decimal: number.decimalValue), currencyCode: "EUR") completion(currencyAmount) } else { completion(nil) } }
3. 确保Siri语言与参数本地化匹配
因为参数标题和提示语用法语,需要将设备的Siri语言设置为法语,避免语音识别的语言不匹配问题。
修改后的完整代码
import AppIntents struct OpenTransaction : AppIntent { static var title: LocalizedStringResource = "Start a transaction" static var openAppWhenRun: Bool = true @Parameter(title: "Montant", currencyCodes: ["EUR"], inclusiveRange: (lowerBound: 0.01, upperBound: 100000000), requestValueDialog: IntentDialog("Une transaction de quel montant ?") ) var amount: IntentCurrencyAmount // 参数解析方法 func resolveAmount(for intentParameter: IntentParameter, with completion: @escaping (IntentCurrencyAmount?) -> Void) { guard let userInput = intentParameter.value as? String else { completion(nil) return } let numberFormatter = NumberFormatter() numberFormatter.locale = Locale(identifier: "fr_FR") numberFormatter.numberStyle = .decimal if let number = numberFormatter.number(from: userInput) { let currencyAmount = IntentCurrencyAmount(amount: NSDecimalNumber(decimal: number.decimalValue), currencyCode: "EUR") completion(currencyAmount) } else { completion(nil) } } @MainActor func perform() async throws -> some IntentResult { print(amount) // 这里调用自研交易框架逻辑 return .result() } static var parameterSummary: some ParameterSummary { Summary("Lancer une transaction de \(\.$amount)") } } struct TapAutoShortcuts : AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: OpenTransaction(), phrases: [ "Lancer une transaction [de \(\.$amount)] avec \(.applicationName)", "Déclencher une transaction [de \(\.$amount)] via \(.applicationName)" ], shortTitle: "Lancer une transaction", systemImageName: "gear" ) } }
内容的提问来源于stack exchange,提问作者EliteSquadron
相关产品推荐
相关产品推荐

