2017-10-05 161 views
0

因此,我剛剛接管了一個iOS項目作爲他們的第一個內部開發者,之前這個應用程序是由一個機構開發的。QR碼掃描不起作用

該應用程序的功能之一是,它需要掃描QR碼 - 通過前面的開發人員遵循的代碼的外觀this教程AppCoda實施QR掃描。一切看起來都很好,我看不出代碼有什麼問題,但它不起作用。

我還下載了完成的教程項目,並且在我嘗試QR掃描時工作。我也嘗試複製和粘貼每一行,以便它與工作教程相同但沒有運氣。

我把我的頭髮撕了出來,試圖找出它爲什麼不工作。

任何幫助非常感謝!

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) { } 

} 

編輯

如果不工作,我的意思是永遠不會被調用爲AVCaptureMetadataOutputObjectsDelegate委託所以它似乎從來沒有被檢測QR碼。在AppCoda教程中,它覆蓋了一個綠色方塊,它檢測到QR碼,但是當我將該代碼放入此應用程序時,這種情況從未發生過。

相機實際上正在運行,但QR碼從未被檢測到。

+1

我覺得也沒關係共享庫,如果我上傳它作爲一個評論,我一直在使用這種吊艙,方便生活,只是想要建議:https://github.com/yannickl/QRCodeReader.swift – Glenn

+0

感謝Glenn,我確實研究過這個,但是當我安裝了pod時,有11個錯誤來自框架,所以我決定只是更容易得到這個實現工作 –

+0

你能給我們更多的細節嗎?當你運行這段代碼時會發生什麼?相機是否在運行?你能看到相機視圖框?您是否嘗試在'didOutput metadataObject'處檢查斷點? – Bluewings

回答

5

原來答案是欺騙性的(和煩人)簡單!當然,在Swift 4中,代表已稍微改名。要解決所有我必須爲改變

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

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

非常感謝!你爲我節省了很多時間:D –

+0

非常感謝你的回答! – Hamsternik

-1

你沒有將你的班級連接到AVCaptureMetadataOutput的代表,這就是爲什麼AVCaptureMetadataOutputObjectsDelegate函數沒有被調用。更多信息:https://developer.apple.com/documentation/avfoundation/avcapturemetadataoutputobjectsdelegate

試試這個:

// 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

感謝您的回答 - 它似乎取得了一些進展。我移動了代碼行,並得到了一個致命的錯誤,說我在'captureMetadataOutput.metadataObjectTypes'中傳遞了一些不受支持的類型,而是使用'availableMetadataObjectTypes'。我這樣做了,但現在'metadataObjectTypes'數組是空的。 –