无需嵌入App,如何为Swift Package测试配置Info.plist权限触发授权?
解决方案:Swift Package测试SFSpeechRecognizer权限问题
直接在Swift Package的独立测试中触发系统语音识别权限弹窗是做不到的——因为Package测试目标没有自己的Info.plist来配置NSSpeechRecognitionUsageDescription,而且测试进程的沙箱限制也不允许弹出系统级权限请求。不过有几个可行的方案满足你的测试需求:
1. 用模拟对象替代真实SFSpeechRecognizer
这是最推荐的方案,既能测试你的业务逻辑,又避开权限限制。核心思路是抽象对SFSpeechRecognizer的依赖:
- 定义一个协议封装你需要的语音识别能力:
protocol SpeechRecognizing { var authorizationStatus: SFSpeechRecognizerAuthorizationStatus { get } func requestAuthorization(completion: @escaping (SFSpeechRecognizerAuthorizationStatus) -> Void) }
- 让
SFSpeechRecognizer扩展实现这个协议:
extension SFSpeechRecognizer: SpeechRecognizing {}
- 你的业务代码依赖
SpeechRecognizing协议而非具体的SFSpeechRecognizer类;测试时用模拟对象返回预期的授权状态:
class MockSpeechRecognizer: SpeechRecognizing { var authorizationStatus: SFSpeechRecognizerAuthorizationStatus = .notDetermined private let completionHandler: ((SFSpeechRecognizerAuthorizationStatus) -> Void)? init(completionHandler: ((SFSpeechRecognizerAuthorizationStatus) -> Void)? = nil) { self.completionHandler = completionHandler } func requestAuthorization(completion: @escaping (SFSpeechRecognizerAuthorizationStatus) -> Void) { completionHandler?(authorizationStatus) completion(authorizationStatus) } }
这样你可以在测试中模拟授权成功、失败、未决定等各种场景,验证你的代码对不同状态的处理逻辑,同时不用依赖真实的系统权限流程。
2. 创建测试宿主App(验证真实框架交互)
如果你确实需要测试和SFSpeechRecognizer的真实交互(比如验证Apple框架的行为是否符合预期),可以给Package配套一个测试App:
- 在你的Package项目中添加一个iOS/macOS App目标;
- 在该App的
Info.plist中添加NSSpeechRecognitionUsageDescription键和对应的描述文本; - 将Package的测试目标关联到这个App上(Xcode中在测试目标的“General”标签下设置“Host Application”);
- 运行App测试时,系统会弹出权限请求弹窗,你可以正常授权后测试真实的语音识别流程。这个方法对Swift Testing和XCTest都适用。
3. 手动授予本地测试权限(仅限开发环境)
如果只是自己本地跑测试,不想额外建App,可以手动给测试进程授权:
- 先随便跑一次Package测试,触发权限请求失败;
- 打开系统偏好设置 → 安全性与隐私 → 隐私 → 语音识别;
- 找到Xcode或者对应的测试进程(比如
xctest),勾选允许它访问语音识别; - 之后再跑测试就能正常调用
SFSpeechRecognizer了。不过这个方法无法在CI环境使用,换机器也需要重新设置,只能作为临时方案。
内容的提问来源于stack exchange,提问作者Grant Neufeld
相关产品推荐
相关产品推荐

