iOS二维码扫描ViewController可显示画面但无法识别二维码求助
解决二维码扫描无响应的问题
嘿,我一眼就看到问题所在啦!你的代码里代理方法的签名不正确,导致系统没办法触发二维码扫描后的回调逻辑。另外还有个小细节可以优化,确保相机权限能正常生效。
问题1:代理方法签名错误
你当前的captureOutput方法是旧的Objective-C兼容写法,在最新的Swift和AVFoundation框架中,AVCaptureMetadataOutputObjectsDelegate的正确代理方法签名已经更新了。系统找不到正确的方法,自然不会执行扫描后的逻辑。
错误的方法:
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { // ... 你的代码 }
替换成正确的方法:
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) }
问题2:缺少主动的相机权限请求
虽然你在Info.plist里加了权限描述,但有时候系统不会自动弹出权限请求(比如用户之前拒绝过),导致相机虽然能启动,但扫描功能可能受限。建议在初始化扫描会话前主动请求权限:
修改你的viewDidLoad方法,把初始化逻辑放到权限请求的回调里:
override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.black // 主动请求相机权限 AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in DispatchQueue.main.async { guard let self = self else { return } if granted { // 权限通过,初始化扫描会话 self.setupCaptureSession() } else { // 提示用户去设置开启权限 let ac = UIAlertController(title: "需要相机权限", message: "请在设置中开启相机权限以使用扫描功能", preferredStyle: .alert) ac.addAction(UIAlertAction(title: "前往设置", style: .default) { _ in guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return } UIApplication.shared.open(settingsURL) }) ac.addAction(UIAlertAction(title: "取消", style: .cancel)) self.present(ac, animated: true) } } } } // 把原来的初始化逻辑抽成单独方法 private func setupCaptureSession() { captureSession = AVCaptureSession() guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { self.failed() return } let videoInput: AVCaptureDeviceInput do { videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) } catch { self.failed() return } if captureSession.canAddInput(videoInput) { captureSession.addInput(videoInput) } else { self.failed() return } let metadataOutput = AVCaptureMetadataOutput() if captureSession.canAddOutput(metadataOutput) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [.qr] } else { self.failed() return } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.frame = view.layer.bounds previewLayer.videoGravity = .resizeAspectFill view.layer.addSublayer(previewLayer) captureSession.startRunning() }
其他检查点
- 确认你的设备支持二维码扫描(大部分现代iOS设备都支持,但模拟器不行,必须用真机测试)
- 确保
metadataOutput.metadataObjectTypes只包含.qr,你当前的设置是对的
做完这两个修改后,你的二维码扫描应该就能正常触发回调啦!
内容的提问来源于stack exchange,提问作者Rutger Huijsmans




