扫描条形码

1、iOS10之后 开启手机的摄像头需要在 Info.plist 里面添加两个键值对

1 Privacy - Photo Library Usage Description
2 Privacy - Camera Usage Description

2、 导入模块 AVFoundation、 遵守 AVCaptureMetadataOutputObjectsDelegate 协议

3、需要真机调用摄像头,不能用模拟器进行测试

 

代码:

  1 import UIKit
  2 import AVFoundation
  3 
  4 class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
  5 
  6     var scanRectView: UIView!
  7     var scanLine: UIImageView!
  8     var timer: Timer!
  9     
 10     var device: AVCaptureDevice!
 11     var input: AVCaptureDeviceInput!
 12     var output: AVCaptureMetadataOutput!
 13     var session: AVCaptureSession!
 14     var preview: AVCaptureVideoPreviewLayer!
 15     
 16     // 摄像头按钮
 17     lazy var cameraBtn: UIButton = {
 18         let cameraBtn = UIButton(frame: CGRect(x: 10, y: self.view.frame.height * 0.8, width: self.view.frame.width - 20, height: 44))
 19         cameraBtn.setTitle("扫一扫", for: .normal)
 20         cameraBtn.setTitleColor(UIColor.orange, for: .normal)
 21         cameraBtn.backgroundColor = UIColor.gray
 22         cameraBtn.addTarget(self, action: #selector(ViewController.fromCamera), for: .touchUpInside)
 23         
 24         return cameraBtn
 25     }()
 26     
 27     override func viewDidLoad() {
 28         super.viewDidLoad()
 29         
 30         self.view.addSubview(self.cameraBtn)
 31     }
 32     
 33 //    MARK: -life cycle
 34     
 35     // 通过摄像头扫描
 36     func fromCamera() {
 37         do {
 38             self.device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
 39             
 40             self.input = try AVCaptureDeviceInput(device: device)
 41             
 42             self.output = AVCaptureMetadataOutput()
 43             output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
 44             
 45             self.session = AVCaptureSession()
 46             if UIScreen.main.bounds.size.height < 500 {
 47                 self.session.sessionPreset = AVCaptureSessionPreset640x480
 48             } else {
 49                 self.session.sessionPreset = AVCaptureSessionPresetHigh
 50             }
 51             
 52             self.session.addInput(self.input)
 53             self.session.addOutput(self.output)
 54             
 55             self.output.metadataObjectTypes = [AVMetadataObjectTypeEAN8Code,
 56                                                AVMetadataObjectTypeEAN13Code,
 57                                                AVMetadataObjectTypeCode128Code,
 58                                                AVMetadataObjectTypeCode93Code]
 59             
 60             // 计算中间可探测区域
 61             let windowSize = UIScreen.main.bounds.size
 62             let scanSize = CGSize(width: windowSize.width * 3 / 4, height: windowSize.height * 3 / 4)
 63             var scanRect = CGRect(x: (windowSize.width - scanSize.width) / 2,
 64                                   y: (windowSize.height - scanSize.height) / 2,
 65                                   width: scanSize.width,
 66                                   height: scanSize.height)
 67             // 计算 rectOfInterset 注意x,y 交换位置
 68             scanRect = CGRect(x: scanRect.origin.y / windowSize.height,
 69                               y: scanRect.origin.x / windowSize.width, width: scanRect.size.height / windowSize.height, height: scanRect.size.width / windowSize.width)
 70             // 设置可探测区域
 71             self.output.rectOfInterest = scanRect
 72             
 73             self.preview = AVCaptureVideoPreviewLayer(session: self.session)
 74             self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill
 75             self.preview.frame = UIScreen.main.bounds
 76             self.view.layer.insertSublayer(self.preview, at: 0)
 77             
 78             // 添加中间的探测区域绿框
 79             self.scanRectView = UIView()
 80             self.view.addSubview(self.scanRectView)
 81             self.scanRectView.frame = CGRect(x: 0, y: 0, width: scanSize.width, height: 100)
 82             print(self.scanRectView.frame)
 83             self.scanRectView.center = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
 84             self.scanRectView.layer.borderColor = UIColor.green.cgColor
 85             self.scanRectView.layer.borderWidth = 1
 86             
 87             // 添加扫描线
 88             self.scanLine = UIImageView()
 89             self.scanLine.frame = CGRect(x: 0, y: 0, width: self.scanRectView.frame.size.width, height: 5)
 90             scanLine.image = UIImage(named: "line3")
 91             // 添加扫描线图层
 92             self.scanRectView.addSubview(self.scanLine)
 93             // 创建定时器, 用于实现扫描线动画
 94             self.timer = Timer()
 95             timer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(ViewController.moveScannerLayer(_:)), userInfo: nil, repeats: true)
 96             
 97             
 98             // 开始捕获
 99             self.session.startRunning()
100             
101             // 放大
102             do {
103                 try self.device.lockForConfiguration()
104             } catch _ {
105                 print("Error: lock For Cpnfuguration.")
106             }
107             self.device.videoZoomFactor = 1.5
108             self.device.unlockForConfiguration()
109         } catch _ {
110             // 打印错误信息
111             // 打印错误消息
112             let alertControl = UIAlertController(title: "提醒", message: "请在 iPhone 的\"设置-隐私-相机\"选项中,允许本程序访问您的相机", preferredStyle: .alert)
113             let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
114             alertControl.addAction(cancelAction)
115             self.present(alertControl, animated: true, completion: nil)
116         }
117     }
118     
119     // 让扫描线滚动
120     func moveScannerLayer(_ timer: Timer) {
121         self.scanLine.frame = CGRect(x: 0, y: 0, width: self.scanRectView.frame.size.width, height: 12)
122         UIView.animate(withDuration: 2) {
123             self.scanLine.frame = CGRect(x: self.scanLine.frame.origin.x,
124                                          y: self.scanLine.frame.origin.y + self.scanRectView.frame.size.height - 10,
125                                          width: self.scanLine.frame.width,
126                                          height: self.scanLine.frame.height)
127         }
128     }
129 
130     
131 //    MARK: -AVCaptureMetadataOutputObjectsDelegate
132     // 摄像头捕获
133     func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
134         
135         var stringValue: String?
136         if metadataObjects.count > 0 {
137             let metadataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
138             stringValue = metadataObject.stringValue
139             if stringValue != nil {
140                 self.session.stopRunning()
141             }
142         }
143         
144         self.session.stopRunning()
145         // 输出结果
146         let alertController = UIAlertController(title: "二维码", message:  stringValue, preferredStyle: .alert)
147         let okAction = UIAlertAction(title: "确定", style: .default) { (action) in
148             // 继续扫描
149             self.session.startRunning()
150         }
151         alertController.addAction(okAction)
152         self.present(alertController, animated: true, completion: nil)
153     }
154     
155     
156 
157     override func didReceiveMemoryWarning() {
158         super.didReceiveMemoryWarning()
159         // Dispose of any resources that can be recreated.
160     }
161 
162 
163 }

 

posted @ 2016-12-14 18:39  人丑多读书丶  阅读(576)  评论(0编辑  收藏  举报