用AVFoundation实现扫描二维码功能

来源:互联网 发布:长沙软件职业学院地址 编辑:程序博客网 时间:2024/05/17 23:34

需要用到的只要几个类:

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



0 0
原创粉丝点击