使用 AVFoudation 框架掃描 QR 碼

在 iOS 7 之前,當你想要掃描 QR 碼時,我們可能需要依賴第三方框架或庫,如 zBarzXing 。但是 Apple 從 iOS 7 中引入了 AVCaptureMetaDataOutput 來讀取條形碼。

要使用 AVFoundation 讀取 QR 碼,我們需要設定/建立 AVCaptureSession 並使用 captureOutput:didOutputMetadataObjects:fromConnection:委託方法。

步驟 1

匯入 AVFoundation 框架並確認 AVCaptureMetadataOutputObjectsDelegate 協議

import AVFoundation
class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate

第 2 步

QR 碼讀取完全基於視訊捕獲。因此,要捕獲連續視訊,請建立一個 AVCaptureSession 並設定裝置輸入和輸出。在檢視控制器 viewDidLoad 方法中新增以下程式碼

// Create an instance of the AVCaptureDevice and provide the video as the media type parameter.
let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
 
do {
    // Create an instance of the AVCaptureDeviceInput class using the device object and intialise capture session
    let input = try AVCaptureDeviceInput(device: captureDevice)
    captureSession = AVCaptureSession()
    captureSession?.addInput(input)
    
    // Create a instance of AVCaptureMetadataOutput object and set it as the output device the capture session.
    let captureMetadataOutput = AVCaptureMetadataOutput()
    captureSession?.addOutput(captureMetadataOutput)
    // Set delegate with a default dispatch queue
    captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
    //set meta data object type as QR code, here we can add more then one type as well 
    captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]

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

    // Start capture session.
    captureSession?.startRunning()
} catch {
    // If any error occurs, let the user know. For the example purpose just print out the error
    print(error)
    return
}

第 3 步

實現 AVCaptureMetadataOutputObjectsDelegate 委託方法來讀取 QR 碼

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
    
    // Check if the metadataObjects array contains at least one object. If not no QR code is in our video capture
    if metadataObjects == nil || metadataObjects.count == 0 {
        // NO QR code is being detected.
        return
    }
    
    // Get the metadata object and cast it to `AVMetadataMachineReadableCodeObject`
    let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
    
    if metadataObj.type == AVMetadataObjectTypeQRCode {
        // If the found metadata is equal to the QR code metadata then get the string value from meta data
        let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
        
        if metadataObj.stringValue != nil {
           // metadataObj.stringValue is our QR code
        }
    }
} 

這裡後設資料物件也可以為你提供在相機源上讀取的 QR 碼的界限。要獲取邊界,只需將後設資料物件傳遞給 videoPreviewLayertransformedMetadataObject 方法,如下所示。

let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
        qrCodeFrameView?.frame = barCodeObject!.bounds