使用 AVFoudation 框架扫描 QR 码
在 iOS 7 之前,当你想要扫描 QR 码时,我们可能需要依赖第三方框架或库,如 zBar 或 zXing 。但是 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 码的界限。要获取边界,只需将元数据对象传递给 videoPreviewLayer
的 transformedMetadataObject
方法,如下所示。
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
qrCodeFrameView?.frame = barCodeObject!.bounds