Swift中基于Apple Intelligence的ShowInAppSearchResultsIntent Siri语音调用异常问题求助
Swift中基于Apple Intelligence的ShowInAppSearchResultsIntent Siri语音调用异常问题求助
看起来你在集成WWDC24推出的ShowInAppSearchResultsIntent和AppShortcutsProvider时遇到了真机与模拟器行为不一致的问题,尤其是真机上出现的Failed to generate TargetContentIdentifier for criteria报错,我来帮你梳理下核心问题和解决方案:
你的问题复盘
- iOS 18模拟器:Siri能正常触发搜索关键词询问,执行
perform方法并弹出alert,但仅为测试阶段的反馈 - 真机环境:直接打开App,不触发Siri的关键词询问,控制台抛出
Failed to generate TargetContentIdentifier for criteria错误
核心原因分析
ShowInAppSearchResultsIntent是Apple Intelligence推出的系统级搜索意图,真机环境对该意图的要求比模拟器更严格:系统需要意图返回可定位到App内搜索内容的TargetContentIdentifier,否则会判定意图不完整,直接跳过参数询问流程打开App。
具体解决方案
1. 为Intent添加TargetContentIdentifier返回
在perform方法中返回带有搜索标识的结果,满足系统对搜索意图的要求:
@MainActor func perform() async throws -> some IntentResult { let searchString = criteria.term print("Searching for \(searchString)") msgWithSingleButton(message: "Searching for \(searchString)", title: "Siri", buttonTitle: "OK") // 生成TargetContentIdentifier,可根据实际搜索结果调整标识规则 let contentIdentifier = TargetContentIdentifier(searchString) // 返回包含对话和标识的结果,同时让Siri播报反馈 return .result( dialog: "Searching for \(searchString) in \(.applicationName)", targetContentIdentifier: contentIdentifier ) }
2. 优化AppShortcut短语的参数绑定
让Siri更精准地将用户语音中的搜索词绑定到criteria参数,减少流程异常:
static var appShortcuts: [AppShortcut] { AppShortcut( intent: CineverseSearchIntent(), phrases: [ "search for \(.parameter(\.criteria)) using \(.applicationName)", "look up \(.parameter(\.criteria)) on \(.applicationName)" ], shortTitle: "Search Movie", systemImageName: "sparkles", openAppWhenRun: true // 明确执行时打开App ) }
3. 确保Intent满足系统搜索意图的配置
在CineverseSearchIntent中添加openAppWhenRun静态属性,明确意图行为:
@AssistantIntent(schema: .system.search) struct CineverseSearchIntent: ShowInAppSearchResultsIntent { static var title: LocalizedStringResource = "Search in Cineverse for" static var searchScopes: [StringSearchScope] = [.general] // 明确执行意图时打开App static var openAppWhenRun: Bool { true } @Parameter(requestValueDialog: IntentDialog("What would you like to search for?")) var criteria: StringSearchCriteria // ... 其他方法不变 }
4. 修复后台唤起时的Alert展示问题
当Siri在后台唤起App时,直接通过UIApplication获取rootViewController可能失败,建议调整msgWithSingleButton方法,确保在App激活时展示:
//Alert @MainActor func msgWithSingleButton(message: String, title: String = "", buttonTitle : String){ guard let scenes = UIApplication.shared.connectedScenes as? [UIWindowScene], let windowScene = scenes.first, let window = windowScene.windows.first else { print("Cannot present alert: App is not active") return } // 如果当前有presented VC,需要在最上层展示 let topVC = window.rootViewController?.presentedViewController ?? window.rootViewController guard let topVC = topVC else { print("Cannot present alert: No root view controller") return } let alertView = UIAlertController(title: title, message: message, preferredStyle: .alert) alertView.addAction(UIAlertAction(title: buttonTitle, style: .default, handler: nil)) topVC.present(alertView, animated: true) }
5. 真机环境的必要设置
- 确保真机已开启Siri与Apple Intelligence(设置 -> Siri与搜索)
- 为你的App开启Siri权限(设置 -> Siri与搜索 -> 找到你的App -> 开启“用Siri唤醒”和“允许Siri建议”)
- 重新安装App到真机,并通过Siri测试快捷短语(比如:"用Cineverse搜索复仇者联盟")
完整修改后的代码
import AppIntents import Foundation import UIKit @AssistantIntent(schema: .system.search) struct CineverseSearchIntent: ShowInAppSearchResultsIntent { static var title: LocalizedStringResource = "Search in Cineverse for" static var searchScopes: [StringSearchScope] = [.general] static var openAppWhenRun: Bool { true } @Parameter(requestValueDialog: IntentDialog("What would you like to search for?")) var criteria: StringSearchCriteria @MainActor func perform() async throws -> some IntentResult { let searchString = criteria.term print("Searching for \(searchString)") msgWithSingleButton(message: "Searching for \(searchString)", title: "Siri", buttonTitle: "OK") let contentIdentifier = TargetContentIdentifier(searchString) return .result( dialog: "Searching for \(searchString) in \(.applicationName)", targetContentIdentifier: contentIdentifier ) } } class AppShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: CineverseSearchIntent(), phrases: [ "search for \(.parameter(\.criteria)) using \(.applicationName)", "look up \(.parameter(\.criteria)) on \(.applicationName)" ], shortTitle: "Search Movie", systemImageName: "sparkles", openAppWhenRun: true ) } } //Alert @MainActor func msgWithSingleButton(message: String, title: String = "", buttonTitle : String){ guard let scenes = UIApplication.shared.connectedScenes as? [UIWindowScene], let windowScene = scenes.first, let window = windowScene.windows.first else { print("Cannot present alert: No active window scene") return } let topVC = window.rootViewController?.presentedViewController ?? window.rootViewController guard let topVC = topVC else { print("Cannot present alert: No root view controller") return } let alertView = UIAlertController(title: title, message: message, preferredStyle: .alert) alertView.addAction(UIAlertAction(title: buttonTitle, style: .default, handler: nil)) topVC.present(alertView, animated: true) }
最后测试建议
- 清理Xcode缓存,删除真机上的旧App
- 重新编译安装,首次打开App时授予Siri权限
- 唤起Siri,测试快捷短语,比如:"用Cineverse搜索钢铁侠"
- 检查控制台是否还有
TargetContentIdentifier报错
备注:内容来源于stack exchange,提问作者Supriyo Dey
相关产品推荐
相关产品推荐

