Swift QR扫描

现在使用iOS自己的AVFoundation库来实现一个扫描二维码/条形码的功能已经相当快捷简单了,并且效率也不比之前一些第三方的框架差了。现在,就动手自己做一个扫描二维码的应用吧。下面是完成后的页面效果:


效果图

要实现这个效果,主要是两方面的工作:

  1. 实现扫描,并得到扫描结果的功能
  2. 绘制扫描页面

要实现扫描功能,第一个要做的工作就是先拿到一个AVCaptureSession对象

var captureSession = AVCaptureSession()

AVCaptureSession这个类的作用就是为了来协调输入流和输出流的。
下面,就需要创建输入流,这里就需要用到相机了

let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .back)
        guard let captureDevice = deviceDiscoverySession.devices.first else {
            print("Failed to get the camera device")
            return
        }

这里的AVCaptureDevice.DiscoverySession用来查询所有指定类型的devices,一般情况下当然都是用后摄像头来扫描,所以我们指定了.back.

得到后摄像头后,我们就可以创建输入流了

let input = try AVCaptureDeviceInput(device: captureDevice)
captureSession?.addInput(input)

创建好input后,把它添加到captureSession里就可以了

接下来,就是创建输出流,并添加到captureSession

captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            
captureMetadataOutput.metadataObjectTypes = [.qr]

这里通过给输出流设置代理来获取扫描结果,并且设置了代理方法执行的线程,以及我们感兴趣的metadata,这里暂时只用来扫描二维码,当然,你也可以设置条码等。

输入输出流设置好之后,还有一个很重要的AVCaptureVideoPreviewLayer需要设置,这个类可以将实时捕获的视频展示出来,我们只需要得到它的一个对象,并添加到我们自己的view.layer上就可以了

            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
            videoPreviewLayer?.videoGravity = .resizeAspectFill
            videoPreviewLayer?.frame = view.layer.bounds
            view.layer.addSublayer(videoPreviewLayer!)

最后,就可以直接调用captureSession?.startRunning()来扫描了。

扫描完成后,在下面的代理方法中就可以得到扫描的结果了:

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

        if metadataObjects.count == 0{
            return
        }

        let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
        if metadataObj.type != AVMetadataObject.ObjectType.qr {
            return
        }
        
        
        if let result = metadataObj.stringValue {
            self.captureSession?.stopRunning()
            // output qr code
            self.delegate?.scanController(self, didFinishScanWithInfo: result)
        }
    }

最后,我们要介绍的就是自定义扫描框的实现逻辑。在开始之前,我们要了解输出流captureMetadataOutput的一个属性rectOfInterest,就是在这个属性里指定了我们感兴趣的扫描范围。我们只需要指定一个CGRect的扫描范围,然后在在view上覆盖一层自定义的view就可以了。由于代码较多,这里就不粘贴具体的实现了。

大家可以在SwiftQRTools这里找到具体的实现。另外,在这个工具里我把具体的实现封装了起来,由于扫描页面不尽相同,所以我提供了相应的代理方法,只要在代理方法里提供你自己定义的SwiftQRScanView的子类就可以了。 同时,里面还提供了生成二维码,从图片读取二维码信息的小功能。

你可能感兴趣的:(Swift QR扫描)