iOS App因相机权限崩溃:已配置NSCameraUsageDescription仍报错
二维码扫描相机权限崩溃问题排查
问题背景
打开二维码扫描视图控制器时App直接崩溃,报错内容如下:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
已反复检查Info.plist文件及Target配置,确认添加了相机权限描述,但错误仍未解决。相关ViewController代码如下:
import UIKit import AVFoundation class Scanner__VC: UIViewController, AVCaptureMetadataOutputObjectsDelegate { var captureSession: AVCaptureSession! var previewLayer: AVCaptureVideoPreviewLayer! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.black captureSession = AVCaptureSession() guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return } let videoInput: AVCaptureDeviceInput do { videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) } catch { return } if (captureSession.canAddInput(videoInput)) { captureSession.addInput(videoInput) } else { failed() return } let metadataOutput = AVCaptureMetadataOutput() if (captureSession.canAddOutput(metadataOutput)) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [.qr] } else { failed() return } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.frame = view.layer.bounds previewLayer.videoGravity = .resizeAspectFill view.layer.addSublayer(previewLayer) captureSession.startRunning() } func failed() { let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .alert) ac.addAction(UIAlertAction(title: "OK", style: .default)) present(ac, animated: true) captureSession = nil } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if (captureSession?.isRunning == false) { captureSession.startRunning() } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if (captureSession?.isRunning == true) { captureSession.stopRunning() } } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { captureSession.stopRunning() if let metadataObject = metadataObjects.first { guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return } guard let stringValue = readableObject.stringValue else { return } AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) found(code: stringValue) } dismiss(animated: true) } func found(code: String) { print(code) } override var prefersStatusBarHidden: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } func showAlert(with message: String) { let alert = UIAlertController(title: "QR Code Scanned", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } }
可能的遗漏配置及修复方案
- 检查权限键名拼写:确保Info.plist中添加的是
NSCameraUsageDescription(注意大小写和完整拼写,避免少写字母或写错单词),iOS 10及以上版本必须使用该键名。 - 确认配置文件对应正确Target:项目中可能存在多个Info.plist(如主App、Extension的配置),需验证添加权限的是当前运行Target对应的Info.plist。可通过Target的「Build Settings」→「Info.plist File」路径确认文件位置。
- 保证权限描述非空:权限对应的字符串值不能为空,必须填写明确的用途说明(例如“需要访问相机以扫描二维码”),空值会被系统判定为未配置权限。
- 清理缓存并重启Xcode:Xcode可能缓存旧配置,执行「Product」→「Clean Build Folder」,重启Xcode后重新编译运行。
- 调整权限申请时机:代码中在
viewDidLoad直接启动captureSession.startRunning(),但iOS要求权限弹窗需由用户交互触发(如按钮点击)。建议将相机启动逻辑移至用户主动操作(比如点击“开始扫描”按钮)之后,避免系统拦截权限申请。 - 验证编译后包的配置:右键点击编译生成的.app文件→「Show Package Contents」,打开其中的Info.plist,确认
NSCameraUsageDescription键和对应值是否存在,验证配置是否被正确打包。
内容的提问来源于stack exchange,提问作者Hamza Imran
相关产品推荐
相关产品推荐

