You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动