No Description

QRCodeScanner.swift 4.8KB

    // // QRCodeScanner.swift // QRView // // Created by FFIB on 2017/7/19. // Copyright © 2017年 FFIB. All rights reserved. // import UIKit import AVFoundation class QRCodeScanner: NSObject { var didDecodeCode: ((QRCodeScanResult) -> Void)? var didDecodeFail: ((NSError) -> Void)? fileprivate let captureSession = AVCaptureSession() fileprivate let input: AVCaptureInput? = { guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return nil } return try? AVCaptureDeviceInput(device: device) }() fileprivate let output = AVCaptureMetadataOutput() var previewLayer: AVCaptureVideoPreviewLayer? fileprivate var avaliable = true var scanRect: CGRect init(scanRect: CGRect) { self.scanRect = scanRect super.init() commonInit() } fileprivate func commonInit() { #if !TARGET_INTERFACE_BUILDER && !((arch(i386) || arch(x86_64))) switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) { case .notDetermined: initCaputue() startCaputue() case .authorized: self.initCaputue() self.startCaputue() default: let alert = UIAlertView(title: "拒绝访问", message: "请在设置-隐私-相机中允许访问相机", delegate: nil, cancelButtonTitle: "确定") alert.show() self.avaliable = false } #endif } fileprivate func initCaputue() { guard let input = self.input else { return } self.captureSession.sessionPreset = AVCaptureSession.Preset.hd1920x1080 if self.captureSession.canAddInput(input) { self.captureSession.addInput(input) } else { self.avaliable = false } if self.captureSession.canAddOutput(self.output) { self.captureSession.addOutput(self.output) self.output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] self.output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) } else { self.avaliable = false } } fileprivate func setScanArea() { //设置扫描区域 let cropRect = CGRect(x: (self.scanRect.width - self.scanRect.width / 1.5) / 2, y: (self.scanRect.height - self.scanRect.width / 1.5) / 2, width: self.scanRect.width / 1.5, height: self.scanRect.width / 1.5) output.rectOfInterest = CGRect(x: cropRect.origin.y / scanRect.height, y: cropRect.origin.x / scanRect.width, width: cropRect.height / scanRect.height, height: cropRect.width / scanRect.width) } fileprivate func startCaputue() { guard avaliable && !captureSession.isRunning else { print("QRCode camera not avaliable") return } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill } func startScan() { setScanArea() // captureSession.startRunning() } func stopScan() { if captureSession.isRunning { captureSession.stopRunning() } } deinit { NotificationCenter.default.removeObserver(self, name: Notification.QRNotification.RestartNotification, object: nil) } func cueSound() { var soundId = SystemSoundID() guard let path = Bundle.main.path(forResource: "di", ofType: "mp3") else { return } let url = URL(fileURLWithPath: path) AudioServicesCreateSystemSoundID(url as CFURL, &soundId) AudioServicesPlaySystemSound(soundId) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) } } extension QRCodeScanner: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { guard let metadatas = metadataObjects as? [AVMetadataMachineReadableCodeObject], let res = metadatas.first?.stringValue, let type = metadataObjects.first?.type.rawValue else { let error = NSError.init(domain: "scan qr code failure", code: 102, userInfo: nil) didDecodeFail!(error) return } stopScan() cueSound() didDecodeCode!(QRCodeScanResult(metadataType: type, result: res)) } }