252 unknown exceptionflutter-beta
| @@ -79,6 +79,7 @@ unlinked_spec.ds | |||||
| **/ios/**/DerivedData/ | **/ios/**/DerivedData/ | ||||
| **/ios/**/Icon? | **/ios/**/Icon? | ||||
| **/ios/**/Pods/ | **/ios/**/Pods/ | ||||
| **/ios/.symlinks/ | |||||
| **/ios/**/.symlinks/ | **/ios/**/.symlinks/ | ||||
| **/ios/**/profile | **/ios/**/profile | ||||
| **/ios/**/xcuserdata | **/ios/**/xcuserdata | ||||
| @@ -21,7 +21,7 @@ class FlutterQrPlugin : FlutterPlugin, ActivityAware { | |||||
| } | } | ||||
| private fun onAttachedToV1(registrar: PluginRegistry.Registrar) { | private fun onAttachedToV1(registrar: PluginRegistry.Registrar) { | ||||
| registrar.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) | |||||
| Shared.registrar = registrar | |||||
| onAttachedToEngines(registrar.platformViewRegistry(), registrar.messenger(), registrar.activity()) | onAttachedToEngines(registrar.platformViewRegistry(), registrar.messenger(), registrar.activity()) | ||||
| } | } | ||||
| @@ -45,27 +45,23 @@ class FlutterQrPlugin : FlutterPlugin, ActivityAware { | |||||
| override fun onAttachedToActivity(activityPluginBinding: ActivityPluginBinding) { | override fun onAttachedToActivity(activityPluginBinding: ActivityPluginBinding) { | ||||
| Shared.activity = activityPluginBinding.activity | Shared.activity = activityPluginBinding.activity | ||||
| activityPluginBinding.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) | |||||
| Shared.binding = activityPluginBinding | |||||
| } | } | ||||
| override fun onDetachedFromActivityForConfigChanges() { | override fun onDetachedFromActivityForConfigChanges() { | ||||
| Shared.activity = null | Shared.activity = null | ||||
| Shared.binding = null | |||||
| } | } | ||||
| override fun onReattachedToActivityForConfigChanges(activityPluginBinding: ActivityPluginBinding) { | override fun onReattachedToActivityForConfigChanges(activityPluginBinding: ActivityPluginBinding) { | ||||
| Shared.activity = activityPluginBinding.activity | Shared.activity = activityPluginBinding.activity | ||||
| Shared.binding = activityPluginBinding | |||||
| } | } | ||||
| override fun onDetachedFromActivity() { | override fun onDetachedFromActivity() { | ||||
| Shared.activity = null | Shared.activity = null | ||||
| Shared.binding = null | |||||
| } | } | ||||
| inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener { | |||||
| override fun onRequestPermissionsResult(id: Int, permissions: Array<String>, grantResults: IntArray): Boolean { | |||||
| if (id == Shared.CAMERA_REQUEST_ID && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -4,40 +4,50 @@ import android.Manifest | |||||
| import android.app.Activity | import android.app.Activity | ||||
| import android.app.Application | import android.app.Application | ||||
| import android.content.pm.PackageManager | import android.content.pm.PackageManager | ||||
| import android.os.Bundle | |||||
| import android.view.View | |||||
| import com.google.zxing.ResultPoint | |||||
| import android.hardware.Camera.CameraInfo | import android.hardware.Camera.CameraInfo | ||||
| import android.os.Build | import android.os.Build | ||||
| import android.os.Bundle | |||||
| import android.view.View | |||||
| import com.google.zxing.BarcodeFormat | import com.google.zxing.BarcodeFormat | ||||
| import com.google.zxing.ResultPoint | |||||
| import com.journeyapps.barcodescanner.BarcodeCallback | import com.journeyapps.barcodescanner.BarcodeCallback | ||||
| import com.journeyapps.barcodescanner.BarcodeResult | import com.journeyapps.barcodescanner.BarcodeResult | ||||
| import com.journeyapps.barcodescanner.BarcodeView | import com.journeyapps.barcodescanner.BarcodeView | ||||
| import io.flutter.plugin.common.BinaryMessenger | import io.flutter.plugin.common.BinaryMessenger | ||||
| import io.flutter.plugin.common.MethodCall | import io.flutter.plugin.common.MethodCall | ||||
| import io.flutter.plugin.common.MethodChannel | import io.flutter.plugin.common.MethodChannel | ||||
| import io.flutter.plugin.common.PluginRegistry | |||||
| import io.flutter.plugin.platform.PlatformView | import io.flutter.plugin.platform.PlatformView | ||||
| class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<String, Any>) : | class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<String, Any>) : | ||||
| PlatformView, MethodChannel.MethodCallHandler { | |||||
| PlatformView, MethodChannel.MethodCallHandler, PluginRegistry.RequestPermissionsResultListener { | |||||
| private var isTorchOn: Boolean = false | private var isTorchOn: Boolean = false | ||||
| private var isPaused: Boolean = false | private var isPaused: Boolean = false | ||||
| private var barcodeView: BarcodeView? = null | private var barcodeView: BarcodeView? = null | ||||
| private val channel: MethodChannel | |||||
| private val channel: MethodChannel = MethodChannel(messenger, "net.touchcapture.qr.flutterqr/qrview_$id") | |||||
| private var permissionGranted: Boolean = false | |||||
| init { | init { | ||||
| checkAndRequestPermission(null) | |||||
| channel = MethodChannel(messenger, "net.touchcapture.qr.flutterqr/qrview_$id") | |||||
| if (Shared.binding != null) { | |||||
| Shared.binding!!.addRequestPermissionsResultListener(this) | |||||
| } | |||||
| if (Shared.registrar != null) { | |||||
| Shared.registrar!!.addRequestPermissionsResultListener(this) | |||||
| } | |||||
| channel.setMethodCallHandler(this) | channel.setMethodCallHandler(this) | ||||
| Shared.activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { | Shared.activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { | ||||
| override fun onActivityPaused(p0: Activity) { | override fun onActivityPaused(p0: Activity) { | ||||
| if (p0 == Shared.activity && !isPaused) { | |||||
| if (p0 == Shared.activity && !isPaused && hasCameraPermission()) { | |||||
| barcodeView?.pause() | barcodeView?.pause() | ||||
| } | } | ||||
| } | } | ||||
| override fun onActivityResumed(p0: Activity) { | override fun onActivityResumed(p0: Activity) { | ||||
| if (p0 == Shared.activity && !isPaused) { | |||||
| if (p0 == Shared.activity && !isPaused && hasCameraPermission()) { | |||||
| barcodeView?.resume() | barcodeView?.resume() | ||||
| } | } | ||||
| } | } | ||||
| @@ -93,20 +103,22 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| if (barcodeView == null) { | if (barcodeView == null) { | ||||
| return barCodeViewNotSet(result) | return barCodeViewNotSet(result) | ||||
| } else if (!hasCameraPermission()) { | } else if (!hasCameraPermission()) { | ||||
| return cameraPermissionNotSet(result) | |||||
| } | |||||
| checkAndRequestPermission(result) | |||||
| } else { | |||||
| barcodeView!!.pause() | |||||
| val settings = barcodeView!!.cameraSettings | |||||
| if(settings.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT) | |||||
| settings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK | |||||
| else | |||||
| settings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT | |||||
| barcodeView!!.pause() | |||||
| val settings = barcodeView!!.cameraSettings | |||||
| barcodeView!!.cameraSettings = settings | |||||
| barcodeView!!.resume() | |||||
| result.success(settings.requestedCameraId) | |||||
| } | |||||
| if(settings.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT) | |||||
| settings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK | |||||
| else | |||||
| settings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT | |||||
| barcodeView!!.cameraSettings = settings | |||||
| barcodeView!!.resume() | |||||
| result.success(settings.requestedCameraId) | |||||
| } | } | ||||
| private fun getFlashInfo(result: MethodChannel.Result) { | private fun getFlashInfo(result: MethodChannel.Result) { | ||||
| @@ -119,8 +131,6 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| private fun toggleFlash(result: MethodChannel.Result) { | private fun toggleFlash(result: MethodChannel.Result) { | ||||
| if (barcodeView == null) { | if (barcodeView == null) { | ||||
| return barCodeViewNotSet(result) | return barCodeViewNotSet(result) | ||||
| } else if (!hasCameraPermission()) { | |||||
| return cameraPermissionNotSet(result) | |||||
| } | } | ||||
| if (hasFlash()) { | if (hasFlash()) { | ||||
| @@ -137,28 +147,28 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| if (barcodeView == null) { | if (barcodeView == null) { | ||||
| return barCodeViewNotSet(result) | return barCodeViewNotSet(result) | ||||
| } else if (!hasCameraPermission()) { | } else if (!hasCameraPermission()) { | ||||
| return cameraPermissionNotSet(result) | |||||
| } | |||||
| if (barcodeView!!.isPreviewActive) { | |||||
| isPaused = true | |||||
| barcodeView!!.pause() | |||||
| checkAndRequestPermission(result) | |||||
| } else { | |||||
| if (barcodeView!!.isPreviewActive) { | |||||
| isPaused = true | |||||
| barcodeView!!.pause() | |||||
| } | |||||
| result.success(true) | |||||
| } | } | ||||
| result.success(true) | |||||
| } | } | ||||
| private fun resumeCamera(result: MethodChannel.Result) { | private fun resumeCamera(result: MethodChannel.Result) { | ||||
| if (barcodeView == null) { | if (barcodeView == null) { | ||||
| return barCodeViewNotSet(result) | return barCodeViewNotSet(result) | ||||
| } else if (!hasCameraPermission()) { | } else if (!hasCameraPermission()) { | ||||
| return cameraPermissionNotSet(result) | |||||
| } | |||||
| if (!barcodeView!!.isPreviewActive) { | |||||
| isPaused = false | |||||
| barcodeView!!.resume() | |||||
| checkAndRequestPermission(result) | |||||
| } else { | |||||
| if (!barcodeView!!.isPreviewActive) { | |||||
| isPaused = false | |||||
| barcodeView!!.resume() | |||||
| } | |||||
| result.success(true) | |||||
| } | } | ||||
| result.success(true) | |||||
| } | } | ||||
| private fun hasFlash(): Boolean { | private fun hasFlash(): Boolean { | ||||
| @@ -182,10 +192,6 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| result.error("404", "No barcode view found", null) | result.error("404", "No barcode view found", null) | ||||
| } | } | ||||
| private fun cameraPermissionNotSet(result: MethodChannel.Result) { | |||||
| result.error("cameraPermission", " Permission denied to access the camera", null) | |||||
| } | |||||
| override fun getView(): View { | override fun getView(): View { | ||||
| return initBarCodeView().apply {}!! | return initBarCodeView().apply {}!! | ||||
| } | } | ||||
| @@ -196,16 +202,17 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| if (params["cameraFacing"] as Int == 1) { | if (params["cameraFacing"] as Int == 1) { | ||||
| barcodeView?.cameraSettings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT | barcodeView?.cameraSettings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT | ||||
| } | } | ||||
| barcodeView!!.resume() | |||||
| } else { | |||||
| if (hasCameraPermission()) { | |||||
| if (!isPaused) barcodeView!!.resume() | |||||
| } else { | |||||
| checkAndRequestPermission(null) | |||||
| } | |||||
| } | } | ||||
| return barcodeView | return barcodeView | ||||
| } | } | ||||
| private fun startScan(arguments: List<Int>?, result: MethodChannel.Result) { | private fun startScan(arguments: List<Int>?, result: MethodChannel.Result) { | ||||
| if (!hasCameraPermission()) { | |||||
| return cameraPermissionNotSet(result) | |||||
| } | |||||
| val allowedBarcodeTypes = mutableListOf<BarcodeFormat>() | val allowedBarcodeTypes = mutableListOf<BarcodeFormat>() | ||||
| try { | try { | ||||
| arguments?.forEach { | arguments?.forEach { | ||||
| @@ -254,7 +261,6 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| private fun checkAndRequestPermission(result: MethodChannel.Result?) { | private fun checkAndRequestPermission(result: MethodChannel.Result?) { | ||||
| when { | when { | ||||
| hasCameraPermission() -> result?.success(true) | |||||
| Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { | Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { | ||||
| Shared.activity?.requestPermissions( | Shared.activity?.requestPermissions( | ||||
| arrayOf(Manifest.permission.CAMERA), | arrayOf(Manifest.permission.CAMERA), | ||||
| @@ -265,5 +271,20 @@ class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<St | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| override fun onRequestPermissionsResult( requestCode: Int, | |||||
| permissions: Array<out String>?, | |||||
| grantResults: IntArray): Boolean { | |||||
| if (requestCode == Shared.CAMERA_REQUEST_ID && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |||||
| permissionGranted = true | |||||
| channel.invokeMethod("onPermissionSet", true) | |||||
| return true | |||||
| } | |||||
| permissionGranted = false | |||||
| channel.invokeMethod("onPermissionSet", false) | |||||
| return false | |||||
| } | |||||
| } | } | ||||
| @@ -1,8 +1,12 @@ | |||||
| package net.touchcapture.qr.flutterqr | package net.touchcapture.qr.flutterqr | ||||
| import android.app.Activity | import android.app.Activity | ||||
| import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding | |||||
| import io.flutter.plugin.common.PluginRegistry | |||||
| object Shared { | object Shared { | ||||
| const val CAMERA_REQUEST_ID = 513469796 | const val CAMERA_REQUEST_ID = 513469796 | ||||
| var activity: Activity? = null | var activity: Activity? = null | ||||
| var binding: ActivityPluginBinding? = null | |||||
| var registrar: PluginRegistry.Registrar? = null | |||||
| } | } | ||||
| @@ -32,6 +32,7 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){ | public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){ | ||||
| self.registrar = registrar | self.registrar = registrar | ||||
| previewView = UIView(frame: frame) | previewView = UIView(frame: frame) | ||||
| scanner = MTBBarcodeScanner(previewView: previewView) | |||||
| cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back | cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back | ||||
| channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | ||||
| } | } | ||||
| @@ -77,226 +78,165 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| return previewView | return previewView | ||||
| } | } | ||||
| func setDimensions(_ result: @escaping FlutterResult, width: Double, height: Double, scanArea: Double, scanAreaOffset: Double) -> Void { | |||||
| func requestPermissions(_ result: @escaping FlutterResult) { | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | ||||
| if permissionGranted { | if permissionGranted { | ||||
| // self?.channel.invokeMethod("onPermissionSet", arguments: true) | |||||
| // First set the size of the preview area. | |||||
| self.previewView.frame = CGRect(x: 0, y: 0, width: width, height: height) | |||||
| // Then set the size of the scan area. | |||||
| let midX = self.view().bounds.midX | |||||
| let midY = self.view().bounds.midY | |||||
| // Check if the scanner is already created. | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if let previewLayer = sc.previewLayer { | |||||
| previewLayer.frame = self.previewView.bounds; | |||||
| } | |||||
| if (scanArea != 0) { | |||||
| sc.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) | |||||
| // Set offset if provided. | |||||
| if (scanAreaOffset != 0) { | |||||
| sc.scanRect = sc.scanRect.offsetBy(dx: 0, dy: CGFloat(scanAreaOffset)) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| // Create a scanner view if it doesn't exist yet. | |||||
| self.scanner = MTBBarcodeScanner(previewView: self.previewView) | |||||
| if (scanArea != 0) { | |||||
| self.scanner?.didStartScanningBlock = { | |||||
| self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) | |||||
| // Set offset if provided. | |||||
| if (scanAreaOffset != 0) { | |||||
| self.scanner?.scanRect = (self.scanner?.scanRect.offsetBy(dx: 0, dy: CGFloat(scanAreaOffset)))! | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return result(width) | |||||
| self.channel.invokeMethod("onPermissionSet", arguments: true) | |||||
| } else { | } else { | ||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | ||||
| } | } | ||||
| }) | }) | ||||
| } | } | ||||
| func startScan(_ arguments: Array<Int>, _ result: @escaping FlutterResult) -> Void { | |||||
| if (scanner == nil) { | |||||
| scanner = MTBBarcodeScanner(previewView: previewView) | |||||
| func setDimensions(_ result: @escaping FlutterResult, width: Double, height: Double, scanArea: Double, scanAreaOffset: Double) { | |||||
| // First ask for permission | |||||
| requestPermissions(result) | |||||
| // Then set the size of the preview area. | |||||
| self.previewView.frame = CGRect(x: 0, y: 0, width: width, height: height) | |||||
| // Then set the size of the scan area. | |||||
| let midX = self.view().bounds.midX | |||||
| let midY = self.view().bounds.midY | |||||
| // Set the size of the preview. | |||||
| if let previewLayer = self.scanner?.previewLayer { | |||||
| previewLayer.frame = self.previewView.bounds | |||||
| } | } | ||||
| // Set scanArea if provided. | |||||
| if (scanArea != 0) { | |||||
| self.scanner?.didStartScanningBlock = { | |||||
| self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) | |||||
| // Set offset if provided. | |||||
| if (scanAreaOffset != 0) { | |||||
| self.scanner?.scanRect = (self.scanner?.scanRect.offsetBy(dx: 0, dy: CGFloat(scanAreaOffset)))! | |||||
| } | |||||
| } | |||||
| } | |||||
| return result(width) | |||||
| } | |||||
| func startScan(_ arguments: Array<Int>, _ result: @escaping FlutterResult) { | |||||
| // Check for allowed barcodes | |||||
| var allowedBarcodeTypes: Array<AVMetadataObject.ObjectType> = [] | var allowedBarcodeTypes: Array<AVMetadataObject.ObjectType> = [] | ||||
| arguments.forEach { arg in | arguments.forEach { arg in | ||||
| allowedBarcodeTypes.append( QRCodeTypes[arg]!) | allowedBarcodeTypes.append( QRCodeTypes[arg]!) | ||||
| } | } | ||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| self.channel.invokeMethod("onPermissionSet", arguments: true) | |||||
| do { | |||||
| try self.scanner?.startScanning(with: self.cameraFacing, resultBlock: { [weak self] codes in | |||||
| if let codes = codes { | |||||
| for code in codes { | |||||
| var typeString: String; | |||||
| switch(code.type) { | |||||
| case AVMetadataObject.ObjectType.aztec: | |||||
| typeString = "AZTEC" | |||||
| case AVMetadataObject.ObjectType.code39: | |||||
| typeString = "CODE_39" | |||||
| case AVMetadataObject.ObjectType.code93: | |||||
| typeString = "CODE_93" | |||||
| case AVMetadataObject.ObjectType.code128: | |||||
| typeString = "CODE_128" | |||||
| case AVMetadataObject.ObjectType.dataMatrix: | |||||
| typeString = "DATA_MATRIX" | |||||
| case AVMetadataObject.ObjectType.ean8: | |||||
| typeString = "EAN_8" | |||||
| case AVMetadataObject.ObjectType.ean13: | |||||
| typeString = "EAN_13" | |||||
| case AVMetadataObject.ObjectType.itf14: | |||||
| typeString = "ITF" | |||||
| case AVMetadataObject.ObjectType.pdf417: | |||||
| typeString = "PDF_417" | |||||
| case AVMetadataObject.ObjectType.qr: | |||||
| typeString = "QR_CODE" | |||||
| case AVMetadataObject.ObjectType.upce: | |||||
| typeString = "UPC_E" | |||||
| default: | |||||
| return | |||||
| } | |||||
| guard let stringValue = code.stringValue else { continue } | |||||
| let result = ["code": stringValue, "type": typeString] | |||||
| if allowedBarcodeTypes.count == 0 || allowedBarcodeTypes.contains(code.type) { | |||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | |||||
| } | |||||
| } | |||||
| do { | |||||
| try self.scanner?.startScanning(with: self.cameraFacing, resultBlock: { [weak self] codes in | |||||
| if let codes = codes { | |||||
| for code in codes { | |||||
| var typeString: String; | |||||
| switch(code.type) { | |||||
| case AVMetadataObject.ObjectType.aztec: | |||||
| typeString = "AZTEC" | |||||
| case AVMetadataObject.ObjectType.code39: | |||||
| typeString = "CODE_39" | |||||
| case AVMetadataObject.ObjectType.code93: | |||||
| typeString = "CODE_93" | |||||
| case AVMetadataObject.ObjectType.code128: | |||||
| typeString = "CODE_128" | |||||
| case AVMetadataObject.ObjectType.dataMatrix: | |||||
| typeString = "DATA_MATRIX" | |||||
| case AVMetadataObject.ObjectType.ean8: | |||||
| typeString = "EAN_8" | |||||
| case AVMetadataObject.ObjectType.ean13: | |||||
| typeString = "EAN_13" | |||||
| case AVMetadataObject.ObjectType.itf14: | |||||
| typeString = "ITF" | |||||
| case AVMetadataObject.ObjectType.pdf417: | |||||
| typeString = "PDF_417" | |||||
| case AVMetadataObject.ObjectType.qr: | |||||
| typeString = "QR_CODE" | |||||
| case AVMetadataObject.ObjectType.upce: | |||||
| typeString = "UPC_E" | |||||
| default: | |||||
| return | |||||
| } | } | ||||
| }) | |||||
| } catch { | |||||
| let error = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: nil) | |||||
| return result(error) | |||||
| guard let stringValue = code.stringValue else { continue } | |||||
| let result = ["code": stringValue, "type": typeString] | |||||
| if allowedBarcodeTypes.count == 0 || allowedBarcodeTypes.contains(code.type) { | |||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| } | |||||
| }) | |||||
| }) | |||||
| } catch { | |||||
| let error = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: nil) | |||||
| return result(error) | |||||
| } | |||||
| } | } | ||||
| func stopCamera(_ result: @escaping FlutterResult){ | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.isScanning() { | |||||
| sc.stopScanning() | |||||
| } | |||||
| } | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| func stopCamera(_ result: @escaping FlutterResult) { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.isScanning() { | |||||
| sc.stopScanning() | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| } | } | ||||
| func getCameraInfo(_ result: @escaping FlutterResult) -> Void { | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| result(sc.camera.rawValue) | |||||
| } else { | |||||
| let error = FlutterError(code: "cameraInformationError", message: "Could not get camera information", details: nil) | |||||
| result(error) | |||||
| } | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| } | |||||
| }) | |||||
| func getCameraInfo(_ result: @escaping FlutterResult) { | |||||
| result(self.cameraFacing.rawValue) | |||||
| } | } | ||||
| func flipCamera(_ result: @escaping FlutterResult){ | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.hasOppositeCamera() { | |||||
| sc.flipCamera() | |||||
| } | |||||
| return result(sc.camera.rawValue) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| func flipCamera(_ result: @escaping FlutterResult) { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.hasOppositeCamera() { | |||||
| sc.flipCamera() | |||||
| self.cameraFacing = sc.camera | |||||
| } | } | ||||
| }) | |||||
| return result(sc.camera.rawValue) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } | } | ||||
| func getFlashInfo(_ result: @escaping FlutterResult) -> Void { | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| result(sc.torchMode.rawValue != 0) | |||||
| } else { | |||||
| let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil) | |||||
| result(error) | |||||
| } | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| } | |||||
| }) | |||||
| func getFlashInfo(_ result: @escaping FlutterResult) { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| result(sc.torchMode.rawValue != 0) | |||||
| } else { | |||||
| let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil) | |||||
| result(error) | |||||
| } | |||||
| } | } | ||||
| func toggleFlash(_ result: @escaping FlutterResult){ | func toggleFlash(_ result: @escaping FlutterResult){ | ||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.hasTorch() { | |||||
| sc.toggleTorch() | |||||
| return result(sc.torchMode == MTBTorchMode(rawValue: 1)) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "This device doesn\'t support flash", details: nil)) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.hasTorch() { | |||||
| sc.toggleTorch() | |||||
| return result(sc.torchMode == MTBTorchMode(rawValue: 1)) | |||||
| } | } | ||||
| }) | |||||
| return result(FlutterError(code: "404", message: "This device doesn\'t support flash", details: nil)) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } | } | ||||
| func pauseCamera(_ result: @escaping FlutterResult) { | func pauseCamera(_ result: @escaping FlutterResult) { | ||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.isScanning() { | |||||
| sc.freezeCapture() | |||||
| } | |||||
| return result(true) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if sc.isScanning() { | |||||
| sc.freezeCapture() | |||||
| } | } | ||||
| }) | |||||
| return result(true) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } | } | ||||
| func resumeCamera(_ result: @escaping FlutterResult) { | func resumeCamera(_ result: @escaping FlutterResult) { | ||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if !sc.isScanning() { | |||||
| sc.unfreezeCapture() | |||||
| } | |||||
| return result(true) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } else { | |||||
| return result(FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)) | |||||
| if let sc: MTBBarcodeScanner = self.scanner { | |||||
| if !sc.isScanning() { | |||||
| sc.unfreezeCapture() | |||||
| } | } | ||||
| }) | |||||
| return result(true) | |||||
| } | |||||
| return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil)) | |||||
| } | } | ||||
| func getSystemFeatures(_ result: @escaping FlutterResult) -> Void { | |||||
| func getSystemFeatures(_ result: @escaping FlutterResult) { | |||||
| if let sc: MTBBarcodeScanner = scanner { | if let sc: MTBBarcodeScanner = scanner { | ||||
| var hasBackCameraVar = false | var hasBackCameraVar = false | ||||
| var hasFrontCameraVar = false | var hasFrontCameraVar = false | ||||
| @@ -0,0 +1,30 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter/foundation.dart'; | |||||
| class LifecycleEventHandler extends WidgetsBindingObserver { | |||||
| LifecycleEventHandler({ | |||||
| this.resumeCallBack, | |||||
| this.suspendingCallBack, | |||||
| }); | |||||
| final AsyncCallback resumeCallBack; | |||||
| final AsyncCallback suspendingCallBack; | |||||
| @override | |||||
| Future<void> didChangeAppLifecycleState(AppLifecycleState state) async { | |||||
| switch (state) { | |||||
| case AppLifecycleState.resumed: | |||||
| if (resumeCallBack != null) { | |||||
| await resumeCallBack(); | |||||
| } | |||||
| break; | |||||
| case AppLifecycleState.inactive: | |||||
| case AppLifecycleState.paused: | |||||
| case AppLifecycleState.detached: | |||||
| if (suspendingCallBack != null) { | |||||
| await suspendingCallBack(); | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||
| import 'lifecycle_event_handler.dart'; | |||||
| import 'qr_scanner_overlay_shape.dart'; | import 'qr_scanner_overlay_shape.dart'; | ||||
| import 'types/barcode.dart'; | import 'types/barcode.dart'; | ||||
| import 'types/barcode_format.dart'; | import 'types/barcode_format.dart'; | ||||
| @@ -58,6 +59,19 @@ class QRView extends StatefulWidget { | |||||
| class _QRViewState extends State<QRView> { | class _QRViewState extends State<QRView> { | ||||
| var _channel; | var _channel; | ||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| WidgetsBinding.instance.addObserver(LifecycleEventHandler( | |||||
| resumeCallBack: () async => { | |||||
| if (_channel != null) | |||||
| { | |||||
| QRViewController.updateDimensions(widget.key, _channel, | |||||
| overlay: widget.overlay) | |||||
| } | |||||
| })); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return NotificationListener( | return NotificationListener( | ||||
| @@ -75,6 +89,7 @@ class _QRViewState extends State<QRView> { | |||||
| QRViewController.updateDimensions(widget.key, _channel, | QRViewController.updateDimensions(widget.key, _channel, | ||||
| overlay: widget.overlay) | overlay: widget.overlay) | ||||
| }); | }); | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -124,9 +139,9 @@ class _QRViewState extends State<QRView> { | |||||
| _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id'); | _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id'); | ||||
| // Start scan after creation of the view | // Start scan after creation of the view | ||||
| final controller = | |||||
| QRViewController._(_channel, widget.key, widget.onPermissionSet) | |||||
| .._startScan(widget.key, widget.overlay, widget.formatsAllowed); | |||||
| final controller = QRViewController._( | |||||
| _channel, widget.key, widget.onPermissionSet, widget.cameraFacing) | |||||
| .._startScan(widget.key, widget.overlay, widget.formatsAllowed); | |||||
| // Initialize the controller for controlling the QRView | // Initialize the controller for controlling the QRView | ||||
| if (widget.onQRViewCreated != null) { | if (widget.onQRViewCreated != null) { | ||||
| @@ -151,8 +166,9 @@ class _QrCameraSettings { | |||||
| class QRViewController { | class QRViewController { | ||||
| QRViewController._(MethodChannel channel, GlobalKey qrKey, | QRViewController._(MethodChannel channel, GlobalKey qrKey, | ||||
| PermissionSetCallback onPermissionSet) | |||||
| : _channel = channel { | |||||
| PermissionSetCallback onPermissionSet, CameraFacing cameraFacing) | |||||
| : _channel = channel, | |||||
| _cameraFacing = cameraFacing { | |||||
| _channel.setMethodCallHandler((call) async { | _channel.setMethodCallHandler((call) async { | ||||
| switch (call.method) { | switch (call.method) { | ||||
| case 'onRecognizeQR': | case 'onRecognizeQR': | ||||
| @@ -189,11 +205,13 @@ class QRViewController { | |||||
| } | } | ||||
| final MethodChannel _channel; | final MethodChannel _channel; | ||||
| final CameraFacing _cameraFacing; | |||||
| final StreamController<Barcode> _scanUpdateController = | final StreamController<Barcode> _scanUpdateController = | ||||
| StreamController<Barcode>(); | StreamController<Barcode>(); | ||||
| Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; | Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; | ||||
| static bool _firstRun = true; | |||||
| SystemFeatures _features; | SystemFeatures _features; | ||||
| bool _hasPermissions; | bool _hasPermissions; | ||||
| @@ -216,6 +234,8 @@ class QRViewController { | |||||
| /// Gets information about which camera is active. | /// Gets information about which camera is active. | ||||
| Future<CameraFacing> getCameraInfo() async { | Future<CameraFacing> getCameraInfo() async { | ||||
| try { | try { | ||||
| var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int; | |||||
| if (cameraFacing == -1) return _cameraFacing; | |||||
| return CameraFacing | return CameraFacing | ||||
| .values[await _channel.invokeMethod('getCameraInfo') as int]; | .values[await _channel.invokeMethod('getCameraInfo') as int]; | ||||
| } on PlatformException catch (e) { | } on PlatformException catch (e) { | ||||
| @@ -299,6 +319,10 @@ class QRViewController { | |||||
| static Future<void> updateDimensions(GlobalKey key, MethodChannel channel, | static Future<void> updateDimensions(GlobalKey key, MethodChannel channel, | ||||
| {QrScannerOverlayShape overlay}) async { | {QrScannerOverlayShape overlay}) async { | ||||
| if (defaultTargetPlatform == TargetPlatform.iOS) { | if (defaultTargetPlatform == TargetPlatform.iOS) { | ||||
| if (_firstRun) { | |||||
| _firstRun = false; | |||||
| await Future.delayed(Duration(milliseconds: 300)); | |||||
| } | |||||
| final RenderBox renderBox = key.currentContext.findRenderObject(); | final RenderBox renderBox = key.currentContext.findRenderObject(); | ||||
| try { | try { | ||||
| await channel.invokeMethod('setDimensions', { | await channel.invokeMethod('setDimensions', { | ||||