为何INShortcut始终无效?Siri快捷方式创建失败排查
问题重现
尝试展示INUIAddVoiceShortcutViewController添加Siri快捷方式时,执行到let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)会输出以下错误日志:
[NSExtension] Extension request contains input items but the extension point does not specify a set of allowed payload classes. The extension point's NSExtensionContext subclass must implement
+_allowedItemPayloadClasses. This must return the set of allowed NSExtensionItem payload classes. In future, this request will fail with an error.
同时调试发现,无论是通过自定义TrackOrderIntent还是NSUserActivity创建的INShortcut实例均处于invalid状态。
核心原因分析
- Intent配置不完整:自定义Intent缺少必填参数、未启用Siri支持,或参数配置不符合要求
- NSUserActivity未声明:activity类型未在
Info.plist中注册,关键属性缺失 - UI操作线程错误:在后台线程执行UI展示操作,导致控制器初始化异常
- 项目配置缺失:未正确配置Siri权限或Intent Extension关联
解决方案
一、针对自定义Intent的修复步骤
完善Intent Definition配置
打开你的.intentdefinition文件,检查TrackOrderIntent:- 确保所有必填参数已定义并设置正确类型
- 勾选
Supports Siri选项,设置合理的Category(如OrderTracking) - 添加至少一个
Suggested Phrase,方便用户调用快捷方式
初始化Intent时赋值必填参数
自动生成的Intent类如果有必填参数,必须在初始化后赋值,否则无法生成有效的shortcut:let customIntent = TrackOrderIntent() // 示例:给必填参数orderId赋值 customIntent.orderId = "ORD-12345" guard let shortcut = INShortcut(intent: customIntent) else { print("无法基于Intent创建有效shortcut") return }
二、针对NSUserActivity的修复步骤
在Info.plist中注册Activity类型
添加NSUserActivityTypes数组,将你的activity标识符group.com.example.trackOrder加入其中:<key>NSUserActivityTypes</key> <array> <string>group.com.example.trackOrder</string> </array>完善NSUserActivity属性设置
确保关键属性不为空,且配置符合Siri快捷要求:let identifier = "group.com.example.trackOrder" let activity = NSUserActivity(activityType: identifier) activity.title = "查询订单状态" activity.persistentIdentifier = NSUserActivityPersistentIdentifier(identifier) activity.isEligibleForSearch = true activity.isEligibleForPrediction = true activity.suggestedInvocationPhrase = "我的订单在哪?" userActivity = activity activity.becomeCurrent() guard let shortcut = INShortcut(userActivity: activity) else { print("无法基于NSUserActivity创建有效shortcut") return }
三、关键通用修复:回到主线程执行UI操作
INPreferences.requestSiriAuthorization的回调在后台线程执行,直接调用present会导致UI异常,必须切换到主线程:
if #available(iOS 12.0, *) { INPreferences.requestSiriAuthorization { status in if status == .authorized { DispatchQueue.main.async { // 切换至主线程 let customIntent = TrackOrderIntent() customIntent.orderId = "ORD-12345" guard let shortcut = INShortcut(intent: customIntent) else { return } let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut) viewController.modalPresentationStyle = .formSheet viewController.delegate = self self.present(viewController, animated: true, completion: nil) } } } }
验证步骤
- 执行
Product > Clean Build Folder清理项目 - 重新Build并运行App
- 调试时检查
shortcut.isValid是否为true,若为true则说明shortcut已有效
内容的提问来源于stack exchange,提问作者Ahmad F

