web-dev-qa-db-fra.com

Scanner le code-barres ou le code QR dans Swift 3.0 en utilisant AVFoundation

Je suis ceci tutoriel et j'ai essayé de convertir les codes sous forme Swift 2.0 à 3.0. Mais quand j'ai lancé l'application, l'application ne fonctionne pas! Je veux dire, rien ne se passe! Voici mon code:

ViewController:

class ViewController: UIViewController ,BarcodeDelegate {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        let barcodeViewController: BarcodeViewController = segue.destination as! BarcodeViewController
        barcodeViewController.delegate = self

    }



    func barcodeReaded(barcode: String) {
        codeTextView.text = barcode
        print(barcode)
    }

}

BarcodeVC:

import AVFoundation


protocol BarcodeDelegate {

    func barcodeReaded(barcode: String)
}

class BarcodeViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate {

    var delegate: BarcodeDelegate?
    var captureSession: AVCaptureSession!
    var code: String?


    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        print("works")

        self.captureSession = AVCaptureSession();
        let videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

        do {

            let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)

            if self.captureSession.canAddInput(videoInput) {
                self.captureSession.addInput(videoInput)
            } else {
                print("Could not add video input")
            }

            let metadataOutput = AVCaptureMetadataOutput()
            if self.captureSession.canAddOutput(metadataOutput) {
                self.captureSession.addOutput(metadataOutput)

                metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code]
            } else {
                print("Could not add metadata output")
            }

            let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
            previewLayer?.frame = self.view.layer.bounds
            self.view.layer .addSublayer(previewLayer!)
            self.captureSession.startRunning()
        } catch let error as NSError {
            print("Error while creating vide input device: \(error.localizedDescription)")
        }



    }



    //I THINK THIS METHOD NOT CALL !
    private func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {

        // This is the delegate'smethod that is called when a code is readed
        for metadata in metadataObjects {
            let readableObject = metadata as! AVMetadataMachineReadableCodeObject
            let code = readableObject.stringValue

            // If the code is not empty the code is ready and we call out delegate to pass the code.
            if  code!.isEmpty {
                print("is empty")

            }else {

                self.captureSession.stopRunning()
                self.dismiss(animated: true, completion: nil)
                self.delegate?.barcodeReaded(barcode: code!)


            }
        }

    }

Voici la sortie:

2016-09-17 18: 10: 26.000919 BarcodeScaning [2610: 674253] [MC] Le conteneur du groupe système pour systemgroup.com.Apple.configurationprofiles est/private/var/containers/Shared/SystemGroup/systemgroup.com.Apple.configurationprofiles 2016-09-17 18: 10: 26.007782 BarcodeScaning [2610: 674253] [MC] Lecture à partir des paramètres utilisateur effectifs publics.

14
Mc.Lover

Voici réponse de Victor Sigler mise à jour vers Swift 4 sans déballage forcé, un protocole faible, exécutant du code coûteux dans le thread d'arrière-plan et autres raffinements.

Notez que la méthode de AVCaptureMetadataOutputObjectsDelegate est passée de

captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)

à

metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)

import UIKit
import AVFoundation

protocol BarcodeDelegate: class {
    func barcodeRead(barcode: String)
}

class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    weak var delegate: BarcodeDelegate?

    var output = AVCaptureMetadataOutput()
    var previewLayer: AVCaptureVideoPreviewLayer!

    var captureSession = AVCaptureSession()

    override func viewDidLoad() {
        super.viewDidLoad()

        setupCamera()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        DispatchQueue.global(qos: .background).async {
            if !self.captureSession.isRunning {
                self.captureSession.startRunning()
            }
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        DispatchQueue.global(qos: .background).async {
            if self.captureSession.isRunning {
                self.captureSession.stopRunning()
            }
        }
    }

    fileprivate func setupCamera() {
        guard let device = AVCaptureDevice.default(for: .video),
            let input = try? AVCaptureDeviceInput(device: device) else {
            return
        }

        DispatchQueue.global(qos: .background).async {
            if self.captureSession.canAddInput(input) {
                self.captureSession.addInput(input)
            }

            let metadataOutput = AVCaptureMetadataOutput()

            if self.captureSession.canAddOutput(metadataOutput) {
                self.captureSession.addOutput(metadataOutput)

                metadataOutput.setMetadataObjectsDelegate(self, queue: .global(qos: .background))

                if Set([.qr, .ean13]).isSubset(of: metadataOutput.availableMetadataObjectTypes) {
                    metadataOutput.metadataObjectTypes = [.qr, .ean13]
                }
            } else {
                print("Could not add metadata output")
            }

            self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
            self.previewLayer.videoGravity = .resizeAspectFill

            DispatchQueue.main.async {
                self.previewLayer.frame = self.view.bounds
                self.view.layer.addSublayer(self.previewLayer)
            }
        }
    }

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        // This is the delegate's method that is called when a code is read
        for metadata in metadataObjects {
            if let readableObject = metadata as? AVMetadataMachineReadableCodeObject,
                let code = readableObject.stringValue {
                dismiss(animated: true)
                delegate?.barcodeRead(barcode: code)
                print(code)
            }
        }
    }
}
8
Tamás Sengel

Scanner de codes-barres dans Swift 4 pour tous les types de codes

Ci-dessous, je voudrais partager avec quelques idées en fonction de la numérisation de codes à barres dans iOS.

  • séparer la logique du scanner de codes-barres de View logic,
  • ajouter une entrée dans le fichier .plist
  • définir exposurePointOfInterest et focusPointOfInterest
  • set rectOfInterests avec CGRect converti approprié
  • définir focusMode et exposureMode
  • verrouiller captureDevice avec lockForConfiguration correctement tout en modifiant les paramètres de capture de la caméra

Ajouter une entrée dans le fichier .plist
Dans le fichier Info.plist, ajoutez le code suivant pour permettre à votre application d'accéder à la caméra de l'iPhone:

<key>NSCameraUsageDescription</key>
<string>Allow access to camera</string>

Définir expositionPointOfInterest et focusPointOfInterest
exposurePointOfInterest et focusPointOfInterest permettent une meilleure qualité de numérisation, une mise au point plus rapide de la caméra sur le point central de l'écran.

Définir rectOfInterests
Cette propriété permet à la caméra de se concentrer uniquement sur une partie de l'écran. De cette façon, le code peut être scanné plus rapidement, concentré uniquement sur les codes présentés au centre de l'écran - ce qui est utile alors que peu d'autres codes sont disponibles en arrière-plan.

Définir focusMode et expositionMode Les propriétés doivent être définies comme suit:

device.focusMode = .continuousAutoFocus
device.exposureMode = .continuousAutoExposure

Cela permet de se concentrer en continu et de régler l'exposition bien ajustée au code de numérisation.

Démo

Ici vous pouvez trouver un projet prêt à mettre en œuvre cette idée: https://github.com/lukszar/QuickScanner

3
lukszar
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
  print("caught QR code")
  for metadata in metadataObjects {
     let readableObject = metadata as! AVMetadataMachineReadableCodeObject
     let code = readableObject.stringValue
     if  code!.isEmpty {
        print("is empty")
     } else {
        self.captureSession.stopRunning()
        self.dismiss(animated: true, completion: nil)
        self.delegate?.gotQRCode(code: code!)
     }
  }
}

On dirait que la signature de la méthode a changé un peu dans Swift 3. Voici la version correcte

1
Mikhail Baynov

Vous devez ajouter NSCameraUsageDescription à votre fichier Info.plist pour le faire fonctionner!

Ajoutez simplement une ligne dans info.plist et tapez NSCameraUsageDescription dans la ligne nouvellement créée et ajoutez une chaîne destinée à informer l'utilisateur des raisons pour lesquelles l'accès à la caméra est nécessaire dans votre application.

Cela devrait faire l'affaire!

1
Johan Tingbacke