2017-10-05 11 views
0

Je viens donc de prendre en charge un projet iOS en tant que leur premier développement interne, où précédemment cette application avait été développée par une agence.QR Code Scanning ne fonctionne pas

L'une des caractéristiques de l'application est qu'elle a besoin de scanner les codes QR - par l'aspect du code que les développeurs précédents ont suivi this tutoriel sur AppCoda pour mettre en œuvre le scan QR. Tout semble bien et je ne vois rien de mal avec le code mais ça ne marche pas.

J'ai également téléchargé le tutoriel terminé et cela a fonctionné lorsque j'ai essayé le scan QR. J'ai également essayé de copier et coller chaque ligne pour qu'elle soit identique au tutoriel de travail mais pas de chance. Je me suis arraché les cheveux en essayant de comprendre pourquoi cela ne fonctionne pas.

Toute aide est très appréciée!

enum ScanState : Int { 
    case newDevice = 1 
    case resetDevice = 2 
    case replaceDevice = 3 
} 

class QRScannerViewController: BaseViewController,AVCaptureMetadataOutputObjectsDelegate { 
    @IBOutlet var scanZoneView: UIView! 
    @IBOutlet var scannerVIew: UIView! 
    @IBOutlet var scanInfoLabel: UILabel! 

    var capturedQR: String? = nil 
    var captureSession:AVCaptureSession? 
    var videoPreviewLayer:AVCaptureVideoPreviewLayer? 
    var qrCodeFrameView:UIView? 
    let supportedBarCodes = [AVMetadataObject.ObjectType.qr, AVMetadataObject.ObjectType.code128, AVMetadataObject.ObjectType.code39, AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.upce, AVMetadataObject.ObjectType.pdf417, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.aztec] 
    var type = "leg scan" 


    var device:Device? 
    var state:ScanState = .newDevice 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    scanInfoLabel.text = "Scan your existing\nleg QR code" 

    self.navigationController?.navigationBar.dark() 

    //self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil) 
    } 

    override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    self.navigationController?.setNavigationBarHidden(false, animated: true) 
    } 

    override func viewDidAppear(_ animated: Bool) { 
    super.viewDidAppear(animated) 
    #if NOHARDWARE 
     moveToNextViewController() 
    #else 
     initiateCapture() 
    #endif 
    } 

    func initiateCapture() { 
    let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) 
    // Get an instance of the AVCaptureDeviceInput class using the previous device object. 
    var error:NSError? 
    let input: AnyObject! 
    do { 
     input = try AVCaptureDeviceInput(device: captureDevice!) as AVCaptureDeviceInput 
    } catch let error1 as NSError { 
     error = error1 
     input = nil 
    } catch _ { 
     input = nil 
    } 

    if (error != nil) { 
     // If any error occurs, simply log the description of it and don't continue any more. 
     print("\(error?.localizedDescription)") 
     return 
    } 
    // Initialize the captureSession object. 
    captureSession = AVCaptureSession() 
    // Set the input device on the capture session. 
    captureSession?.addInput(input as! AVCaptureInput) 

    // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. 
    let captureMetadataOutput = AVCaptureMetadataOutput() 
    captureSession?.addOutput(captureMetadataOutput) 

    // Set delegate and use the default dispatch queue to execute the call back 
    captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 
    captureMetadataOutput.metadataObjectTypes = supportedBarCodes 

    // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer. 
    videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!) 
    videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill 
    videoPreviewLayer?.frame = scannerVIew.layer.bounds 
    scannerVIew.layer.addSublayer(videoPreviewLayer!) 

    // Start video capture. 
    captureSession?.startRunning() 


    // Initialize QR Code Frame to highlight the QR code 
    qrCodeFrameView = UIView() 
    qrCodeFrameView?.layer.borderColor = UIColor.green.cgColor 
    qrCodeFrameView?.layer.borderWidth = 2 
    scannerVIew.addSubview(qrCodeFrameView!) 
    scannerVIew.bringSubview(toFront: qrCodeFrameView!) 
    //qrCapturedLabel.text = "No QR code is detected" 

    } 

    override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
    } 

    func metadataOutput(captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 

    // Check if the metadataObjects array is not nil and it contains at least one object. 
    if metadataObjects == nil || metadataObjects.count == 0 { 
     qrCodeFrameView?.frame = CGRect.zero 

     return 
    } 

    // Get the metadata object. 
    let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject 

    // Here we use filter method to check if the type of metadataObj is supported 
    // Instead of hardcoding the AVMetadataObjectTypeQRCode, we check if the type 
    // can be found in the array of supported bar codes. 
    if supportedBarCodes.filter({ $0 == metadataObj.type }).count > 0 { 
     // If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds 
     let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject 

     let intersectionRect = barCodeObject.bounds.intersection(self.scanZoneView.frame) 

     if !intersectionRect.isNull && 
     (intersectionRect.size.width * intersectionRect.size.height) > self.scanZoneView.bounds.width * self.scanZoneView.bounds.height/7 { 

     qrCodeFrameView?.frame = barCodeObject.bounds 

     if process(metadataObj.stringValue!) { 
      captureSession?.stopRunning() 
     } 
     } 
    } 
    } 

    @IBAction func didTapCancel(_ sender: AnyObject) { 
    self.dismiss(animated: true, completion: nil) 
    } 
} 

extension QRScannerViewController { 


    func process(_ scanText : String) -> Bool { 

    var legCode : String 

    let codeComponents = scanText.components(separatedBy: ";") 
    if codeComponents.count > 0 { 
     legCode = codeComponents[0] 
    } else { 
     // Invalid number of parameters seperated by a ; 
     return false 
    } 

    // TODO Validate the LEG to LEG-XXXXX 
    if legCode.hasPrefix("LEG-") { 
     let delta: Int64 = 1 * Int64(NSEC_PER_SEC) 
     let time = DispatchTime.now() + Double(delta)/Double(NSEC_PER_SEC) 

     DispatchQueue.main.asyncAfter(deadline: time, execute: { 

     switch self.state { 

     case .resetDevice: 

      let realm = try! Realm() 
      let deviceList = realm.objects(Device.self) 
      let lc = legCode 

      self.device = deviceList.filter("legCode = %@", lc).first 

      if self.device == nil { 

      // TODO Error message: Device not associated with LEG 
      let vc = ErrorViewController.createErrorViewController(.DeviceNotFound) 
      self.present(vc, animated: true, completion: nil) 
      return 
      } 

      self.moveToNextViewController() 

     default: 
      self.presentingViewController?.dismiss(animated: true, completion: nil) 
     } 

     }); 

     return true 
    } 

    return false 
    } 

    func moveToNextViewController() { 
    let inspectionStoryboard = UIStoryboard(name: "Impact", bundle: nil) 

    if let resetVC = inspectionStoryboard.instantiateViewController(withIdentifier: ImpactDetectionViewController.storyboardID) as? ImpactDetectionViewController { 
     resetVC.device = device 
     // TODO Pass the impact type across too when the G2 API is set 
     self.navigationController?.pushViewController(resetVC, animated: false) 
    } 
    } 

    @IBAction func cancelToVC(_ segue: UIStoryboardSegue) { } 

} 

EDIT

En ne fonctionne pas, je veux dire le délégué pour AVCaptureMetadataOutputObjectsDelegate est jamais appelé il ne semble jamais être détecter un code QR. Dans le tutoriel AppCoda, il recouvre un carré vert où il détecte le code QR, mais cela ne se produit jamais lorsque je mets ce code dans cette application.

La caméra est en cours d'exécution mais les codes QR ne sont jamais détectés.

+1

Je pense qu'il est normal de partager une bibliothèque si je poste un commentaire, je me sers de ce pod pour la vie facile, il suffit Je voudrais suggérer: https://github.com/yannickl/QRCodeReader.swift – Glenn

+0

Merci Glenn, j'ai regardé ça mais quand j'ai installé le pod il y avait 11 erreurs venant du framework alors j'ai décidé que ça serait juste plus facile cette mise en œuvre fonctionne –

+0

Pouvez-vous nous donner plus de détails? Que se passe-t-il lorsque vous exécutez ce code? La caméra fonctionne-t-elle? Pouvez-vous voir les cadres de vue de la caméra? Avez-vous essayé de vérifier avec le point d'arrêt à''didOutput metadataObject'? – Bluewings

Répondre

5

Active la réponse était trompeusement (et agaçante) simples! Bien sûr, dans Swift 4, les délégués ont été légèrement renommés. Pour corriger tout ce que je devais était changer

func metadataOutput(captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 

à

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

Merci beaucoup bro! vous m'avez sauvé beaucoup de temps: D –

+0

Merci beaucoup pour votre réponse! – Hamsternik

-1

Vous ne connectez pas votre classe au délégué AVCaptureMetadataOutput, c'est pourquoi les fonctions AVCaptureMetadataOutputObjectsDelegate ne sont pas appelées. Plus d'infos: https://developer.apple.com/documentation/avfoundation/avcapturemetadataoutputobjectsdelegate

Essayez ceci:

// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. 
    let captureMetadataOutput = AVCaptureMetadataOutput() 
    captureMetadataOutput.metadataObjectsDelegate = self // assign self to the delegate. 
    captureSession?.addOutput(captureMetadataOutput) 
+0

Merci pour votre réponse, il semble avoir fait quelques progrès. Je me suis déplacé autour des lignes de code et ai eu une erreur fatale en disant que je passais des types non supportés dans 'captureMetadataOutput.metadataObjectTypes' et à utiliser' availableMetadataObjectTypes' à la place. Je l'ai fait mais maintenant le tableau 'metadataObjectTypes' est vide. –