The QR Code Scanner package for Appeto SDK.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

304 lines
13 KiB

  1. //
  2. // QRView.swift
  3. // flutter_qr
  4. //
  5. // Created by Julius Canute on 21/12/18.
  6. //
  7. import Foundation
  8. import MTBBarcodeScanner
  9. public class QRView:NSObject,FlutterPlatformView {
  10. @IBOutlet var previewView: UIView!
  11. var scanner: MTBBarcodeScanner?
  12. var registrar: FlutterPluginRegistrar
  13. var channel: FlutterMethodChannel
  14. var cameraFacing: MTBCamera
  15. // Codabar, maxicode, rss14 & rssexpanded not supported. Replaced with qr.
  16. // UPCa uses ean13 object.
  17. var QRCodeTypes = [
  18. 0: AVMetadataObject.ObjectType.aztec,
  19. 1: AVMetadataObject.ObjectType.qr,
  20. 2: AVMetadataObject.ObjectType.code39,
  21. 3: AVMetadataObject.ObjectType.code93,
  22. 4: AVMetadataObject.ObjectType.code128,
  23. 5: AVMetadataObject.ObjectType.dataMatrix,
  24. 6: AVMetadataObject.ObjectType.ean8,
  25. 7: AVMetadataObject.ObjectType.ean13,
  26. 8: AVMetadataObject.ObjectType.interleaved2of5,
  27. 9: AVMetadataObject.ObjectType.qr,
  28. 10: AVMetadataObject.ObjectType.pdf417,
  29. 11: AVMetadataObject.ObjectType.qr,
  30. 12: AVMetadataObject.ObjectType.qr,
  31. 13: AVMetadataObject.ObjectType.qr,
  32. 14: AVMetadataObject.ObjectType.ean13,
  33. 15: AVMetadataObject.ObjectType.upce
  34. ]
  35. public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){
  36. self.registrar = registrar
  37. previewView = UIView(frame: frame)
  38. cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back
  39. channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger())
  40. }
  41. deinit {
  42. scanner?.stopScanning()
  43. }
  44. public func view() -> UIView {
  45. channel.setMethodCallHandler({
  46. [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
  47. switch(call.method){
  48. case "setDimensions":
  49. let arguments = call.arguments as! Dictionary<String, Double>
  50. self?.setDimensions(result,
  51. width: arguments["width"] ?? 0,
  52. height: arguments["height"] ?? 0,
  53. scanArea: arguments["scanAreaWidth"] ?? 0,
  54. scanArea: arguments["scanAreaHeight"] ?? 0,
  55. scanAreaOffset: arguments["scanAreaOffset"] ?? 0)
  56. case "startScan":
  57. self?.startScan(call.arguments as! Array<Int>, result)
  58. case "flipCamera":
  59. self?.flipCamera(result)
  60. case "toggleFlash":
  61. self?.toggleFlash(result)
  62. case "pauseCamera":
  63. self?.pauseCamera(result)
  64. case "stopCamera":
  65. self?.stopCamera(result)
  66. case "resumeCamera":
  67. self?.resumeCamera(result)
  68. case "getCameraInfo":
  69. self?.getCameraInfo(result)
  70. case "getFlashInfo":
  71. self?.getFlashInfo(result)
  72. case "getSystemFeatures":
  73. self?.getSystemFeatures(result)
  74. default:
  75. result(FlutterMethodNotImplemented)
  76. return
  77. }
  78. })
  79. return previewView
  80. }
  81. func setDimensions(_ result: @escaping FlutterResult, width: Double, height: Double, scanAreaWidth: Double, scanAreaHeight: Double, scanAreaOffset: Double) {
  82. // Then set the size of the preview area.
  83. previewView.frame = CGRect(x: 0, y: 0, width: width, height: height)
  84. // Then set the size of the scan area.
  85. let midX = self.view().bounds.midX
  86. let midY = self.view().bounds.midY
  87. if let sc: MTBBarcodeScanner = scanner {
  88. // Set the size of the preview if preview is already created.
  89. if let previewLayer = sc.previewLayer {
  90. previewLayer.frame = self.previewView.bounds
  91. }
  92. } else {
  93. // Create new preview.
  94. scanner = MTBBarcodeScanner(previewView: previewView)
  95. }
  96. // Set scanArea if provided.
  97. if (scanAreaWidth != 0 && scanAreaHeight != 0) {
  98. scanner?.didStartScanningBlock = {
  99. self.scanner?.scanRect = CGRect(x: Double(midX) - (scanAreaWidth / 2), y: Double(midY) - (scanAreaHeight / 2), width: scanAreaWidth, height: scanAreaHeight)
  100. // Set offset if provided.
  101. if (scanAreaOffset != 0) {
  102. let reversedOffset = -scanAreaOffset
  103. self.scanner?.scanRect = (self.scanner?.scanRect.offsetBy(dx: 0, dy: CGFloat(reversedOffset)))!
  104. }
  105. }
  106. }
  107. return result(width)
  108. }
  109. func startScan(_ arguments: Array<Int>, _ result: @escaping FlutterResult) {
  110. // Check for allowed barcodes
  111. var allowedBarcodeTypes: Array<AVMetadataObject.ObjectType> = []
  112. arguments.forEach { arg in
  113. allowedBarcodeTypes.append( QRCodeTypes[arg]!)
  114. }
  115. MTBBarcodeScanner.requestCameraPermission(success: { [weak self] permissionGranted in
  116. guard let self = self else { return }
  117. self.channel.invokeMethod("onPermissionSet", arguments: permissionGranted)
  118. if permissionGranted {
  119. do {
  120. try self.scanner?.startScanning(with: self.cameraFacing, resultBlock: { [weak self] codes in
  121. if let codes = codes {
  122. for code in codes {
  123. var typeString: String;
  124. switch(code.type) {
  125. case AVMetadataObject.ObjectType.aztec:
  126. typeString = "AZTEC"
  127. case AVMetadataObject.ObjectType.code39:
  128. typeString = "CODE_39"
  129. case AVMetadataObject.ObjectType.code93:
  130. typeString = "CODE_93"
  131. case AVMetadataObject.ObjectType.code128:
  132. typeString = "CODE_128"
  133. case AVMetadataObject.ObjectType.dataMatrix:
  134. typeString = "DATA_MATRIX"
  135. case AVMetadataObject.ObjectType.ean8:
  136. typeString = "EAN_8"
  137. case AVMetadataObject.ObjectType.ean13:
  138. typeString = "EAN_13"
  139. case AVMetadataObject.ObjectType.itf14,
  140. AVMetadataObject.ObjectType.interleaved2of5:
  141. typeString = "ITF"
  142. case AVMetadataObject.ObjectType.pdf417:
  143. typeString = "PDF_417"
  144. case AVMetadataObject.ObjectType.qr:
  145. typeString = "QR_CODE"
  146. case AVMetadataObject.ObjectType.upce:
  147. typeString = "UPC_E"
  148. default:
  149. return
  150. }
  151. let bytes = { () -> Data? in
  152. switch (code.descriptor) {
  153. case let qrDescriptor as CIQRCodeDescriptor:
  154. return qrDescriptor.errorCorrectedPayload
  155. case let aztecDescriptor as CIAztecCodeDescriptor:
  156. return aztecDescriptor.errorCorrectedPayload
  157. case let pdf417Descriptor as CIPDF417CodeDescriptor:
  158. return pdf417Descriptor.errorCorrectedPayload
  159. case let dataMatrixDescriptor as CIDataMatrixCodeDescriptor:
  160. return dataMatrixDescriptor.errorCorrectedPayload
  161. default:
  162. return nil
  163. }
  164. }()
  165. let result = { () -> [String : Any]? in
  166. guard let stringValue = code.stringValue else {
  167. guard let safeBytes = bytes else {
  168. return nil
  169. }
  170. return ["type": typeString, "rawBytes": safeBytes]
  171. }
  172. guard let safeBytes = bytes else {
  173. return ["code": stringValue, "type": typeString]
  174. }
  175. return ["code": stringValue, "type": typeString, "rawBytes": safeBytes]
  176. }()
  177. guard let safeResult = result else { continue }
  178. if allowedBarcodeTypes.count == 0 || allowedBarcodeTypes.contains(code.type) {
  179. self?.channel.invokeMethod("onRecognizeQR", arguments: result)
  180. }
  181. }
  182. }
  183. })
  184. } catch {
  185. let scanError = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: error)
  186. result(scanError)
  187. }
  188. } else {
  189. let error = FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)
  190. result(error)
  191. }
  192. })
  193. }
  194. func stopCamera(_ result: @escaping FlutterResult) {
  195. if let sc: MTBBarcodeScanner = self.scanner {
  196. if sc.isScanning() {
  197. sc.stopScanning()
  198. }
  199. }
  200. }
  201. func getCameraInfo(_ result: @escaping FlutterResult) {
  202. result(self.cameraFacing.rawValue)
  203. }
  204. func flipCamera(_ result: @escaping FlutterResult) {
  205. if let sc: MTBBarcodeScanner = self.scanner {
  206. if sc.hasOppositeCamera() {
  207. sc.flipCamera()
  208. self.cameraFacing = sc.camera
  209. }
  210. return result(sc.camera.rawValue)
  211. }
  212. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  213. }
  214. func getFlashInfo(_ result: @escaping FlutterResult) {
  215. if let sc: MTBBarcodeScanner = self.scanner {
  216. result(sc.torchMode.rawValue != 0)
  217. } else {
  218. let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil)
  219. result(error)
  220. }
  221. }
  222. func toggleFlash(_ result: @escaping FlutterResult){
  223. if let sc: MTBBarcodeScanner = self.scanner {
  224. if sc.hasTorch() {
  225. sc.toggleTorch()
  226. return result(sc.torchMode == MTBTorchMode(rawValue: 1))
  227. }
  228. return result(FlutterError(code: "404", message: "This device doesn\'t support flash", details: nil))
  229. }
  230. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  231. }
  232. func pauseCamera(_ result: @escaping FlutterResult) {
  233. if let sc: MTBBarcodeScanner = self.scanner {
  234. if sc.isScanning() {
  235. sc.freezeCapture()
  236. }
  237. return result(true)
  238. }
  239. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  240. }
  241. func resumeCamera(_ result: @escaping FlutterResult) {
  242. if let sc: MTBBarcodeScanner = self.scanner {
  243. if !sc.isScanning() {
  244. sc.unfreezeCapture()
  245. }
  246. return result(true)
  247. }
  248. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  249. }
  250. func getSystemFeatures(_ result: @escaping FlutterResult) {
  251. if let sc: MTBBarcodeScanner = scanner {
  252. var hasBackCameraVar = false
  253. var hasFrontCameraVar = false
  254. let camera = sc.camera
  255. if(camera == MTBCamera(rawValue: 0)){
  256. hasBackCameraVar = true
  257. if sc.hasOppositeCamera() {
  258. hasFrontCameraVar = true
  259. }
  260. }else{
  261. hasFrontCameraVar = true
  262. if sc.hasOppositeCamera() {
  263. hasBackCameraVar = true
  264. }
  265. }
  266. return result([
  267. "hasFrontCamera": hasFrontCameraVar,
  268. "hasBackCamera": hasBackCameraVar,
  269. "hasFlash": sc.hasTorch(),
  270. "activeCamera": camera.rawValue
  271. ])
  272. }
  273. return result(FlutterError(code: "404", message: nil, details: nil))
  274. }
  275. }