TestFlight用户相机权限异常:请求不触发、授权后扫码失效
解决TestFlight环境下相机权限授权后无法启动扫码器的问题
我之前在TestFlight上也踩过类似的权限坑,结合你的代码和场景,几个关键点可以逐一排查:
1. 权限回调的线程问题(最可能的核心原因)
AVCaptureDevice.requestAccess(for: .video)的completion handler是在后台线程执行的,而你直接在回调里调用self.willPresentQRScanner(true)——UI相关操作必须在主线程执行,TestFlight环境下(尤其是经过编译优化的版本),后台线程的UI操作可能被系统拦截或失效。
修改你的requestCameraPermission方法,把UI操作强制切回主线程:
func requestCameraPermission() { AVCaptureDevice.requestAccess(for: .video, completionHandler: { accessGranted in DispatchQueue.main.async { // 切换到主线程执行UI操作 if accessGranted { self.willPresentQRScanner(true) } else { // 补充拒绝后的反馈,避免用户无感知 self.promptForCameraAccess() } } }) }
2. 用户从设置返回后重新检查权限状态
当用户从设置页面允许相机权限回到App时,你的App不会自动触发权限状态重新检测。需要在App激活时主动重新检查,确保状态更新:
方式1:通过通知监听App激活
在你的扫码页面ViewController中添加监听:
override func viewDidLoad() { super.viewDidLoad() // 监听App激活通知 NotificationCenter.default.addObserver( self, selector: #selector(recheckCameraPermission), name: UIApplication.didBecomeActiveNotification, object: nil ) } @objc private func recheckCameraPermission() { proceedWithCameraAccess() } // 页面销毁时移除监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) }
方式2:在SceneDelegate/AppDelegate中处理
如果是iOS 13+的Scene场景,在SceneDelegate的sceneDidBecomeActive方法里触发检查:
func sceneDidBecomeActive(_ scene: UIScene) { // 通过通知触发扫码页面重新检查权限 NotificationCenter.default.post(name: UIApplication.didBecomeActiveNotification, object: nil) }
3. 扫码器初始化的状态重置
如果用户之前拒绝过权限,你的AVCaptureSession可能已经处于失败状态,即使后来权限允许,旧的session实例也无法正常启动。确保willPresentQRScanner方法每次调用时都重新初始化相机会话,不要复用旧实例:
func willPresentQRScanner(_ present: Bool) { guard present else { return } // 重新创建AVCaptureSession let session = AVCaptureSession() session.sessionPreset = .photo guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else { presentCustomAlert(title: "Error", message: "No camera available.") return } do { let input = try AVCaptureDeviceInput(device: camera) if session.canAddInput(input) { session.addInput(input) } // 配置二维码输出逻辑 let output = AVCaptureMetadataOutput() if session.canAddOutput(output) { session.addOutput(output) output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) output.metadataObjectTypes = [.qr] } // 启动会话并展示扫码界面 session.startRunning() let scannerVC = QRScannerViewController(session: session) self.present(scannerVC, animated: true) } catch { presentCustomAlert(title: "Error", message: "Failed to initialize camera.") } }
4. 再次确认info.plist权限描述的正确性
虽然你说已经配置,但TestFlight打包时可能出现plist文件被优化遗漏的情况,务必再次检查:
- 确保存在
NSCameraUsageDescription(iOS 10+)或Privacy - Camera Usage Description的key - 描述文本不能为空,必须清晰说明相机用途(比如"需要相机权限扫描二维码")
额外测试建议
可以让TestFlight用户尝试以下步骤排查:
- 完全退出App(划掉后台)后重新打开,再尝试扫码
- 在设置里先关闭相机权限,再重新打开,然后回到App测试
内容的提问来源于stack exchange,提问作者user12090953
相关产品推荐
相关产品推荐

