You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:41:47