暫無描述

QRCodeScanner.swift 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //
  2. // QRCodeScanner.swift
  3. // QRView
  4. //
  5. // Created by LISA on 2017/7/19.
  6. // Copyright © 2017年 FFIB. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. class QRCodeScanner: NSObject {
  11. var didDecodeCode: ((QRCodeScanResult) -> Void)?
  12. var didDecodeFail: ((NSError) -> Void)?
  13. fileprivate let captureSession = AVCaptureSession()
  14. fileprivate let input: AVCaptureInput? = {
  15. guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return nil }
  16. return try? AVCaptureDeviceInput(device: device)
  17. }()
  18. fileprivate let output = AVCaptureMetadataOutput()
  19. var previewLayer: AVCaptureVideoPreviewLayer?
  20. fileprivate var avaliable = true
  21. var scanRect: CGRect
  22. init(scanRect: CGRect) {
  23. self.scanRect = scanRect
  24. super.init()
  25. commonInit()
  26. }
  27. fileprivate func commonInit() {
  28. #if !TARGET_INTERFACE_BUILDER && !((arch(i386) || arch(x86_64)))
  29. switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
  30. case .notDetermined:
  31. initCaputue()
  32. startCaputue()
  33. break
  34. case .authorized:
  35. self.initCaputue()
  36. self.startCaputue()
  37. break
  38. default:
  39. let alert = UIAlertView(title: "拒绝访问", message: "请在设置-隐私-相机中允许访问相机", delegate: nil, cancelButtonTitle: "确定")
  40. alert.show()
  41. self.avaliable = false
  42. break
  43. }
  44. #endif
  45. }
  46. fileprivate func initCaputue() {
  47. guard let input = self.input else { return }
  48. self.captureSession.sessionPreset = AVCaptureSession.Preset.hd1920x1080
  49. if self.captureSession.canAddInput(input) {
  50. self.captureSession.addInput(input)
  51. } else {
  52. self.avaliable = false
  53. }
  54. if self.captureSession.canAddOutput(self.output) {
  55. self.captureSession.addOutput(self.output)
  56. self.output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
  57. self.output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
  58. } else {
  59. self.avaliable = false
  60. }
  61. }
  62. fileprivate func setScanArea() {
  63. //设置扫描区域
  64. let cropRect = CGRect(x: (self.scanRect.width - self.scanRect.width / 1.5) / 2,
  65. y: (self.scanRect.height - self.scanRect.width / 1.5) / 2,
  66. width: self.scanRect.width / 1.5,
  67. height: self.scanRect.width / 1.5)
  68. output.rectOfInterest = CGRect(x: cropRect.origin.y / scanRect.height,
  69. y: cropRect.origin.x / scanRect.width,
  70. width: cropRect.height / scanRect.height,
  71. height: cropRect.width / scanRect.width)
  72. }
  73. fileprivate func startCaputue() {
  74. guard avaliable && !captureSession.isRunning else {
  75. print("QRCode camera not avaliable")
  76. return
  77. }
  78. previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
  79. previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
  80. }
  81. func startScan() {
  82. setScanArea()
  83. captureSession.startRunning()
  84. }
  85. func stopScan() {
  86. if captureSession.isRunning {
  87. captureSession.stopRunning()
  88. }
  89. }
  90. deinit {
  91. NotificationCenter.default.removeObserver(self, name: Notification.QRNotification.RestartNotification, object: nil)
  92. }
  93. func cueSound() {
  94. var soundId = SystemSoundID()
  95. AudioServicesCreateSystemSoundID(URL.init(fileURLWithPath: Bundle.main.path(forResource: "di", ofType: "mp3")!) as CFURL, &soundId)
  96. AudioServicesPlaySystemSound(soundId)
  97. AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
  98. }
  99. }
  100. extension QRCodeScanner: AVCaptureMetadataOutputObjectsDelegate {
  101. func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
  102. guard let metadatas = metadataObjects as? [AVMetadataMachineReadableCodeObject],
  103. let res = metadatas.first?.stringValue, let type = metadataObjects.first?.type.rawValue else {
  104. let error = NSError.init(domain: "scan qr code failure",
  105. code: 102,
  106. userInfo: nil)
  107. didDecodeFail!(error)
  108. return
  109. }
  110. stopScan()
  111. cueSound()
  112. didDecodeCode!(QRCodeScanResult(metadataType: type, result: res))
  113. }
  114. }