Search code examples
swiftcameraavfoundationqr-code

Why unable to scan QRCode with "AVFoundation" in Swift


I have implemented QRCode scanner in Xcode 14.2 using AVFoundation with below code

code: when i run this code in device then camera is opened but not able to scan QRCode why? where am i wrong. how to scan QRCode using AVFoundation. please help me.

did i miss anything in below code. please guide me

if i run in simulator it says you are running in simulator

class QRCodeScannerVC: 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: AVMediaType.video) else{
        print("you are running in simulator")
        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 = [AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.pdf417]
    } else {
        failed()
        return
    }
    
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession);
    previewLayer.frame = view.layer.bounds;
    previewLayer.videoGravity = AVLayerVideoGravity.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
    print("in simulator")
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    if (captureSession?.isRunning == false) {
        DispatchQueue.global(qos: .background).async {
            self.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 {
        let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject;
        
        AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
        found(code: readableObject.stringValue!);
    }
    dismiss(animated: true)
}

func found(code: String) {
    print(code)
    self.showSingleButtonAlertWithoutAction(title: code)
}
override var prefersStatusBarHidden: Bool {
    return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}
}

Solution

  • I am not sure but this may be the reason and providing this much of text in comment would not be readable so posting it as an answer

    In your code, you specified the metadata object types to scan as [AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.pdf417]. Make sure the QR codes you are trying to scan fall into one of these categories. If you're scanning regular QR codes, you should use AVMetadataObject.ObjectType.qr instead.

    Replace this line:

    metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.pdf417]
    

    With this line:

    metadataOutput.metadataObjectTypes = [.qr]
    

    I hope if the issue is with QR code type then this will help!