The QR Code Scanner package for Appeto SDK.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

305 lignes
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. scanAreaWidth: arguments["scanAreaWidth"] ?? 0,
  54. scanAreaHeight: 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. if #available(iOS 11.0, *) {
  153. switch (code.descriptor) {
  154. case let qrDescriptor as CIQRCodeDescriptor:
  155. return qrDescriptor.errorCorrectedPayload
  156. case let aztecDescriptor as CIAztecCodeDescriptor:
  157. return aztecDescriptor.errorCorrectedPayload
  158. case let pdf417Descriptor as CIPDF417CodeDescriptor:
  159. return pdf417Descriptor.errorCorrectedPayload
  160. case let dataMatrixDescriptor as CIDataMatrixCodeDescriptor:
  161. return dataMatrixDescriptor.errorCorrectedPayload
  162. default:
  163. return nil
  164. }
  165. } else {
  166. return nil
  167. }
  168. }()
  169. let result = { () -> [String : Any]? in
  170. guard let stringValue = code.stringValue else {
  171. guard let safeBytes = bytes else {
  172. return nil
  173. }
  174. return ["type": typeString, "rawBytes": safeBytes]
  175. }
  176. guard let safeBytes = bytes else {
  177. return ["code": stringValue, "type": typeString]
  178. }
  179. return ["code": stringValue, "type": typeString, "rawBytes": safeBytes]
  180. }()
  181. guard result != nil else { continue }
  182. if allowedBarcodeTypes.count == 0 || allowedBarcodeTypes.contains(code.type) {
  183. self?.channel.invokeMethod("onRecognizeQR", arguments: result)
  184. }
  185. }
  186. }
  187. })
  188. } catch {
  189. let scanError = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: error)
  190. result(scanError)
  191. }
  192. }
  193. })
  194. }
  195. func stopCamera(_ result: @escaping FlutterResult) {
  196. if let sc: MTBBarcodeScanner = self.scanner {
  197. if sc.isScanning() {
  198. sc.stopScanning()
  199. }
  200. }
  201. }
  202. func getCameraInfo(_ result: @escaping FlutterResult) {
  203. result(self.cameraFacing.rawValue)
  204. }
  205. func flipCamera(_ result: @escaping FlutterResult) {
  206. if let sc: MTBBarcodeScanner = self.scanner {
  207. if sc.hasOppositeCamera() {
  208. sc.flipCamera()
  209. self.cameraFacing = sc.camera
  210. }
  211. return result(sc.camera.rawValue)
  212. }
  213. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  214. }
  215. func getFlashInfo(_ result: @escaping FlutterResult) {
  216. if let sc: MTBBarcodeScanner = self.scanner {
  217. result(sc.torchMode.rawValue != 0)
  218. } else {
  219. let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil)
  220. result(error)
  221. }
  222. }
  223. func toggleFlash(_ result: @escaping FlutterResult){
  224. if let sc: MTBBarcodeScanner = self.scanner {
  225. if sc.hasTorch() {
  226. sc.toggleTorch()
  227. return result(sc.torchMode == MTBTorchMode(rawValue: 1))
  228. }
  229. return result(FlutterError(code: "404", message: "This device doesn\'t support flash", details: nil))
  230. }
  231. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  232. }
  233. func pauseCamera(_ result: @escaping FlutterResult) {
  234. if let sc: MTBBarcodeScanner = self.scanner {
  235. if sc.isScanning() {
  236. sc.freezeCapture()
  237. }
  238. return result(true)
  239. }
  240. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  241. }
  242. func resumeCamera(_ result: @escaping FlutterResult) {
  243. if let sc: MTBBarcodeScanner = self.scanner {
  244. if !sc.isScanning() {
  245. sc.unfreezeCapture()
  246. }
  247. return result(true)
  248. }
  249. return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
  250. }
  251. func getSystemFeatures(_ result: @escaping FlutterResult) {
  252. if let sc: MTBBarcodeScanner = scanner {
  253. var hasBackCameraVar = false
  254. var hasFrontCameraVar = false
  255. let camera = sc.camera
  256. if(camera == MTBCamera(rawValue: 0)){
  257. hasBackCameraVar = true
  258. if sc.hasOppositeCamera() {
  259. hasFrontCameraVar = true
  260. }
  261. }else{
  262. hasFrontCameraVar = true
  263. if sc.hasOppositeCamera() {
  264. hasBackCameraVar = true
  265. }
  266. }
  267. return result([
  268. "hasFrontCamera": hasFrontCameraVar,
  269. "hasBackCamera": hasBackCameraVar,
  270. "hasFlash": sc.hasTorch(),
  271. "activeCamera": camera.rawValue
  272. ])
  273. }
  274. return result(FlutterError(code: "404", message: nil, details: nil))
  275. }
  276. }