有思俱乐部学习园地

摄像头扫描二维码


Info.plist 配置

由于苹果安全策略更新,在使用 Xcode8 开发时,需要在 Info.plist 配置请求摄像头的相关描述字段(Privacy - Camera Usage Description)
Alternate Text

在主视图ViewController中

添加一个button 给这个button加上点击事件用来跳转到扫一扫页面
Alternate Text

在摄像头视图view2中

导入头文件 import AVFoundation   获取摄像设备
Alternate Text
        主要方法介绍:
        AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
        AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
        AVCaptureDevice代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
        AVCaptureMetadataOutput是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
        AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。

        定义以上变量。

        下一步定义一个与storyboard关联的函数 fromcamera(任意名)
        @IBAction func fromCamera(_ sender: AnyObject){
        //print("调用扫一扫功成功")。调试语句
        do{
            self.device = AVCaptureDevice.default(for: AVMediaType.video)
            //调用摄像头
            self.input = try AVCaptureDeviceInput(device: device)
            //创建输入流 如果没有检测到设备则执行try catch语句
            self.output = AVCaptureMetadataOutput()
            //创建捕获输出流
            output.setMetadataObjectsDelegate(self as AVCaptureMetadataOutputObjectsDelegate, queue: DispatchQueue.main)
            //处理输出捕获会话协议 协议方法在指定的派发队列(DispatchQueue queue)上执行。 实现方法
            self.session = AVCaptureSession()
            //创建会话
            if UIScreen.main.bounds.size.height<500{
                self.session.sessionPreset = AVCaptureSession.Preset.vga640x480
                // 如果 设备的高小于500?
                //则摄像头捕捉的大小为640*480?
            }else{
                self.session.sessionPreset = AVCaptureSession.Preset.high
                //否则将检测到的高赋值给sessionPreset
            }
            
            self.session.addInput(self.input)
            //加入到输入流
            self.session.addOutput(self.output)
            //加入到输出流
            self.output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
            //将读码功能给output
            let windowSize = UIScreen.main.bounds.size
            //获取屏幕的大小
            let scanSize = CGSize(width:windowSize.width*2/3, height:windowSize.width*2/3)
            //使用scanSize来保存windowSize的当前宽高
            var scanRect = CGRect(x:(windowSize.width-scanSize.width)/2,//用scanRect来保持矩形当前的位置和大小     x:扫描框的第一个x坐标
                                  y:(windowSize.height-scanSize.height)/2,// y:扫描框的第一个y坐标
                                  
                                  width:scanSize.width,height:scanSize.height)// x:扫描框的大小
            
            //执行多一次转换成rectOfInterest认识的参数
            scanRect = CGRect(x:scanRect.origin.y/windowSize.height,
                              y:scanRect.origin.x/windowSize.width,
                              width:scanRect.size.height/windowSize.height,
                              height:scanRect.size.width/windowSize.width);
            //实现背景虚化
            print(scanRect)
            background()
            
            
            //设置可探测区域
            self.output.rectOfInterest = scanRect
            
            self.preview = AVCaptureVideoPreviewLayer(session:self.session)
            //扫描到宽高
            self.preview.videoGravity = AVLayerVideoGravity.resizeAspectFill
            //定义摄像头则图层边界矩形内显示的宽高?
            self.preview.frame = UIScreen.main.bounds
            //摄像头获取到的大小。 占满屏幕
            self.view.layer.insertSublayer(self.preview, at: 0)
            //将它插入子图层
            //添加中间的探测区域绿框
            self.scanRectview = UIView();
            //创建 一个视图
            self.view.addSubview(self.scanRectview)
            //将它加入到view中
            self.scanRectview.frame = CGRect(x:0,y:0,width:scanSize.width,
                                             height:scanSize.height);
            //居中
            self.scanRectview.center = CGPoint(x:UIScreen.main.bounds.midX,
                                               y:UIScreen.main.bounds.midY)
            //边框的颜色
            self.scanRectview.layer.borderColor = UIColor.white.cgColor
            //边框的宽度
            self.scanRectview.layer.borderWidth = 1;
            
            //添加yyy
//            let juxing = UIView(frame:CGRect(x:(scanRect.origin.y/windowSize.height),//获取第二个x的坐标
//                y:scanRect.origin.x/windowSize.width,//获取第二个y的坐标
//                width:scanRect.size.height/windowSize.height,
//                height:scanRect.size.width/windowSize.width));
//            juxing.backgroundColor = UIColor.red
//            self.view.addSubview(juxing)
//
            //开始捕获
            self.session.startRunning()
        }catch _{
            print("失败lo")
            //捕捉失败后执行弹框提示
            let alertController = UIAlertController(title:"提醒",
                                                    message:"请在iphone的\"设置-隐私-相机\"选项中,允许本程序访问相机",
                                                    preferredStyle:.alert)
            let cancelAction = UIAlertAction(title:"确定",style:.cancel,handler:nil)
            alertController.addAction(cancelAction)
            self.present(alertController,animated: true,completion: nil)
        }

         func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        //定义一个stringValue来保存捕捉到的信息
        var stringValue:String?
        if metadataObjects.count > 0{
            let metadataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
            stringValue = metadataObject.stringValue
            //解析结果
            print(stringValue)
            if stringValue != nil{
                self.session.startRunning()
            }
        }
        self.session.stopRunning()
        //判断结果是否为有效网址
        //如果为有效网址则用wkview打开
        //否则用弹窗的形式将其显示出来
        if let urll = URL(string: stringValue!){
            if UIApplication.shared.canOpenURL(urll){
                wkview(urll: stringValue!)
            }else{
                alertfun(stringvalue: stringValue!)
            }
        }else{
            alertfun(stringvalue: stringValue!)
        }
    }
    @objc func alertfun(stringvalue: String){
        let alertController = UIAlertController(title:"二维码",
                                                message:stringvalue,preferredStyle:.alert)
        let okAction = UIAlertAction(title:"确定",style:.default,handler:{
            action in
            self.session.startRunning()
        })
        alertController.addAction(okAction)
        self.present(alertController,animated: true,completion: nil)
    }
    @objc func wkview(urll: String){
        let wkwebview = WKWebViewConfiguration()
        let myURL = URL(string:urll)
        let webview = WKWebView(frame:view.bounds,configuration:wkwebview)
        let myRequest = URLRequest(url:myURL!)
        webview.load(myRequest)
        view.addSubview(webview)
        print("加载完毕")
    }
    }
Alternate Text Alternate Text Alternate Text Alternate Text Alternate Text Alternate Text
效果图:(真机缺少 借用网图)
Alternate Text
成功!

工作人员

 
作者:丁志钢
信息录入:丁志钢