需要用到的只要几个类:
AVCaptureSession:管理输入和输出流,包含开启和停止会话方法
AVCaptureDeviceInput:是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化
AVCaptureDevice:代表了物理捕获设备如摄像机。
AVCaptureMetadataOutput:是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
AVCaptureVideoPreviewLayer:CALayer的一个子类,显示捕获到的相机输出流。
用一张图来解释着几个类在具体工作时时如何协调的:
解释一下:首先我们需要一个AVCaptureSession会话,这个是连接输入数据和输出数据的桥梁:
会话创建好了,我们还会需要输入和输出对象:
//输入设备
privatelazy var deviceInput: AVCaptureDeviceInput?= {
// 获取摄像头
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
do {
// 创建输入对象
let device = try AVCaptureDeviceInput.init(device: device)
return device
}catch {
print(error)
let fatal:NSError = error as NSError
// 没有权限访问相机
if fatal.code == -11852 {
let alert = UIAlertController.init(title:"微博没有权限访问您的相机", message: "请您进入设置-隐私-相机为我们开启权限", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction.init(title:"我知道了", style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
return nil
}
}()
//输出对象
privatelazy var outPut: AVCaptureMetadataOutput= AVCaptureMetadataOutput()
预览视图:
private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session:self.session)
layer.frame = UIScreen.mainScreen().bounds
return layer
}()
由此,输入设备,会话,输出,预览视图都已准备就绪,然后开始进行二维码的扫描:
// MARK:开始扫描二维码
privatefunc startScan() {
// 1、判断是否能够将输入添加到会话中
if !session.canAddInput(deviceInput) {
return
}
// 2、判断是否能够将输出添加到会话中
if !session.canAddOutput(outPut) {
return
}
// 3、将输入和输出都添加到会话中
session.addInput(deviceInput)
session.addOutput(outPut)
// 4、设置输出能够解析的数据类型(默认包含二维码类型)
// 这个设置必须是在输出对象被添加到会话之后
outPut.metadataObjectTypes = outPut.availableMetadataObjectTypes
print(outPut.availableMetadataObjectTypes)
// 5、设置输出对象的代理,只要解析成功就会通知这个代理
outPut.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
// 添加预览视图
view.layer.insertSublayer(previewLayer, atIndex:0)
// 6、告诉session开始扫描
session.startRunning()
}
注意第五步中我们将self设置为了输出对象的代理,点开这个协议,你会发现只有一个代理方法:
这个方法只要相机扫描到可以解析的数据就会被调用,扫描结果储存在metadataObjects这个数组中,由于现在我们只需要二维码,所以
加一些判断:
func captureOutput(captureOutput: AVCaptureOutput!,didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!){
print(metadataObjects)
if metadataObjects.count > 0 {
let code: AVMetadataMachineReadableCodeObject = metadataObjects.lastas!AVMetadataMachineReadableCodeObject
let type = code.type
if type.containsString("QRCode") {
// 扫描结果为二维码
let result = code.stringValue
handleResult(result)
}else {
return
}
}
}
然后再加一个处理结果方法打开链接:
/**
处理扫描结果
- parameter result: 扫描结果
*/
func handleResult(result: String) {
// 停止扫描
stopScan()
// 打开地址
if UIApplication.sharedApplication().canOpenURL(NSURL.init(string: result)!) {
UIApplication.sharedApplication().openURL(NSURL.init(string: result)!)
}
}
/**
停止扫描
*/
func stopScan() {
self.scanImage.layer.removeAllAnimations()
session.stopRunning()
session.removeInput(deviceInput)
session.removeOutput(outPut)
// 预览图层从视图层中移除
previewLayer.removeFromSuperlayer()
}