Sfoglia il codice sorgente

Merge pull request #213 from juliuscanute/86-select-camera-on-start

86 select camera on start
flutter-beta
Julian Steenbakker 5 anni fa
committed by GitHub
parent
commit
e80ac88edd
Non sono state trovate chiavi note per questa firma nel database ID Chiave GPG: 4AEE18F83AFDEB23
18 ha cambiato i file con 801 aggiunte e 385 eliminazioni
  1. +0
    -1
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt
  2. +130
    -60
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt
  3. +3
    -2
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt
  4. +0
    -1
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt
  5. +1
    -0
      example/.gitignore
  6. +39
    -39
      example/ios/Runner.xcodeproj/project.pbxproj
  7. +39
    -69
      example/lib/main.dart
  8. +1
    -1
      example/pubspec.yaml
  9. +160
    -58
      ios/Classes/QRView.swift
  10. +2
    -2
      ios/Classes/QRViewFactory.swift
  11. +5
    -0
      lib/qr_code_scanner.dart
  12. +196
    -151
      lib/src/qr_code_scanner.dart
  13. +16
    -0
      lib/src/types/barcode.dart
  14. +174
    -0
      lib/src/types/barcode_format.dart
  15. +7
    -0
      lib/src/types/camera.dart
  16. +14
    -0
      lib/src/types/camera_exception.dart
  17. +13
    -0
      lib/src/types/features.dart
  18. +1
    -1
      pubspec.yaml

+ 0
- 1
android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt Vedi File

@@ -63,7 +63,6 @@ class FlutterQrPlugin : FlutterPlugin, ActivityAware {
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) {
Shared.cameraPermissionContinuation?.run()
return true
}
return false


+ 130
- 60
android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt Vedi File

@@ -3,13 +3,13 @@ package net.touchcapture.qr.flutterqr
import android.Manifest
import android.app.Activity
import android.app.Application
import android.content.Context
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.os.Build
import com.google.zxing.BarcodeFormat
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.BarcodeView
@@ -17,12 +17,11 @@ import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView
class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) :
class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<String, Any>) :
PlatformView, MethodChannel.MethodCallHandler {

private var isTorchOn: Boolean = false
private var barcodeView: BarcodeView? = null
private var requestingPermission = false
private val channel: MethodChannel

init {
@@ -65,89 +64,173 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context)
}

override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when(call.method){
"flipCamera" -> {
flipCamera()
}
"toggleFlash" -> {
toggleFlash()
}
"pauseCamera" -> {
pauseCamera()
}
"resumeCamera" -> {
resumeCamera()
}
when(call.method) {
"startScan" -> startScan(call.arguments as? List<Int>, result)
"stopScan" -> stopScan()
"flipCamera" -> flipCamera(result)
"toggleFlash" -> toggleFlash(result)
"pauseCamera" -> pauseCamera(result)
"resumeCamera" -> resumeCamera(result)
"requestPermissions" -> checkAndRequestPermission(result)
"getCameraInfo" -> getCameraInfo(result)
"getFlashInfo" -> getFlashInfo(result)
"getSystemFeatures" -> getSystemFeatures(result)
else -> result.notImplemented()
}
}

private fun flipCamera() {
barcodeView?.pause()
val settings = barcodeView?.cameraSettings
private fun getCameraInfo(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
result.success(barcodeView!!.cameraSettings.requestedCameraId)
}

private fun flipCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
barcodeView!!.pause()
val settings = barcodeView!!.cameraSettings

if(settings?.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT)
if(settings.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT)
settings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK
else
settings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
settings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT

barcodeView?.cameraSettings = settings
barcodeView?.resume()
barcodeView!!.cameraSettings = settings
barcodeView!!.resume()
result.success(settings.requestedCameraId)
}

private fun toggleFlash() {
private fun getFlashInfo(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
result.success(isTorchOn)
}

private fun toggleFlash(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}

if (hasFlash()) {
barcodeView?.setTorch(!isTorchOn)
barcodeView!!.setTorch(!isTorchOn)
isTorchOn = !isTorchOn
result.success(isTorchOn)
} else {
result.error("404", "This device doesn't support flash", null)
}

}

private fun pauseCamera() {
private fun pauseCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
if (barcodeView!!.isPreviewActive) {
barcodeView?.pause()
barcodeView!!.pause()
}
result.success(true)
}

private fun resumeCamera() {
private fun resumeCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
if (!barcodeView!!.isPreviewActive) {
barcodeView?.resume()
barcodeView!!.resume()
}
result.success(true)
}

private fun hasFlash(): Boolean {
return context.packageManager
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
return hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
}

private fun hasBackCamera(): Boolean {
return hasSystemFeature(PackageManager.FEATURE_CAMERA)
}

private fun hasFrontCamera(): Boolean {
return hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
}

private fun hasSystemFeature(feature: String): Boolean {
return Shared.activity!!.packageManager
.hasSystemFeature(feature)
}

private fun barCodeViewNotSet(result: MethodChannel.Result) {
result.error("404", "No barcode view found", null)
}

override fun getView(): View {
return initBarCodeView()?.apply {
if (!hasBackCamera()) {
if (!hasFrontCamera()) {
// No camera available!
} else {
this.cameraSettings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
}
} else {
this.cameraSettings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK
}
resume()
}!!
}

private fun initBarCodeView(): BarcodeView? {
if (barcodeView == null) {
barcodeView = createBarCodeView()
barcodeView = BarcodeView(Shared.activity)
if (params["cameraFacing"] as Int == 1) {
barcodeView?.cameraSettings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
}
}
return barcodeView
}

private fun createBarCodeView(): BarcodeView {
val barcode = BarcodeView(Shared.activity)
barcode.decodeContinuous(
private fun startScan(arguments: List<Int>?, result: MethodChannel.Result) {
val allowedBarcodeTypes = mutableListOf<BarcodeFormat>()
try {
arguments?.forEach {
allowedBarcodeTypes.add(BarcodeFormat.values()[it])
}
} catch (e: java.lang.Exception) {
result.error(null, null, null)
}

barcodeView?.decodeContinuous(
object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) {
val code = mapOf(
"code" to result.text,
"type" to result.barcodeFormat.name,
"rawBytes" to result.rawBytes)
channel.invokeMethod("onRecognizeQR", code)
if (allowedBarcodeTypes.size == 0 || allowedBarcodeTypes.contains(result.barcodeFormat)) {
val code = mapOf(
"code" to result.text,
"type" to result.barcodeFormat.name,
"rawBytes" to result.rawBytes)
channel.invokeMethod("onRecognizeQR", code)
}

}

override fun possibleResultPoints(resultPoints: List<ResultPoint>) {}
}
)
return barcode
}

private fun stopScan() {
barcodeView?.stopDecoding()
}

private fun getSystemFeatures(result: MethodChannel.Result) {
try {
result.success(mapOf("hasFrontCamera" to hasFrontCamera(),
"hasBackCamera" to hasBackCamera(), "hasFlash" to hasFlash(),
"activeCamera" to barcodeView?.cameraSettings?.requestedCameraId))
} catch (e: Exception) {
result.error(null, null, null)
}
}

private fun hasCameraPermission(): Boolean {
@@ -156,29 +239,16 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context)
}

private fun checkAndRequestPermission(result: MethodChannel.Result?) {
if (Shared.cameraPermissionContinuation != null) {
result?.error("cameraPermission", "Camera permission request ongoing", null)
}

Shared.cameraPermissionContinuation = Runnable {
Shared.cameraPermissionContinuation = null
if (!hasCameraPermission()) {
result?.error(
"cameraPermission", "MediaRecorderCamera permission not granted", null)
return@Runnable
}
}

requestingPermission = false
if (hasCameraPermission()) {
Shared.cameraPermissionContinuation?.run()
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestingPermission = true
when {
hasCameraPermission() -> result?.success(true)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
Shared.activity?.requestPermissions(
arrayOf(Manifest.permission.CAMERA),
Shared.CAMERA_REQUEST_ID)
}
else -> {
result?.error("cameraPermission", "Platform Version to low for camera permission check", null)
}
}
}
}


+ 3
- 2
android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt Vedi File

@@ -10,8 +10,9 @@ import io.flutter.plugin.platform.PlatformViewFactory
class QRViewFactory(private val messenger: BinaryMessenger) :
PlatformViewFactory(StandardMessageCodec.INSTANCE) {

override fun create(context: Context, id: Int, obj: Any?): PlatformView {
return QRView(messenger, id, context)
override fun create(context: Context, id: Int, args: Any?): PlatformView {
val params = args as HashMap<String, Any>
return QRView(messenger, id, params)
}

}

+ 0
- 1
android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt Vedi File

@@ -5,5 +5,4 @@ import android.app.Activity
object Shared {
const val CAMERA_REQUEST_ID = 513469796
var activity: Activity? = null
var cameraPermissionContinuation: Runnable? = null
}

+ 1
- 0
example/.gitignore Vedi File

@@ -9,6 +9,7 @@
.buildlog/
.history
.svn/
.last_build_id

# IntelliJ related
*.iml


+ 39
- 39
example/ios/Runner.xcodeproj/project.pbxproj Vedi File

@@ -9,11 +9,11 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4FA3805501F593094264678B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75B64521967C76C845268E71 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F50BD2AA150CE43D961DBB69 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
@@ -30,15 +30,14 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
11A772D5271EABFB7473B52C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
08F42BD28C1585A831B4FDA2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4D86354DC939411D3F7E41EA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
75B64521967C76C845268E71 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
96DCE88542EFC8C39614159F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -46,7 +45,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DB8991B7B046D94B2E68CEAD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
EF8A0739582463E296AD6CB1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
@@ -54,21 +54,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F50BD2AA150CE43D961DBB69 /* Pods_Runner.framework in Frameworks */,
4FA3805501F593094264678B /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
509AC3E235E568B6DDAAEC7D /* Frameworks */ = {
isa = PBXGroup;
children = (
C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -87,7 +79,7 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
D7C58E57CAF69D9A14CC212F /* Pods */,
509AC3E235E568B6DDAAEC7D /* Frameworks */,
AF031A634C9742F16BF4F89A /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -122,12 +114,20 @@
name = "Supporting Files";
sourceTree = "<group>";
};
AF031A634C9742F16BF4F89A /* Frameworks */ = {
isa = PBXGroup;
children = (
75B64521967C76C845268E71 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
D7C58E57CAF69D9A14CC212F /* Pods */ = {
isa = PBXGroup;
children = (
4D86354DC939411D3F7E41EA /* Pods-Runner.debug.xcconfig */,
11A772D5271EABFB7473B52C /* Pods-Runner.release.xcconfig */,
96DCE88542EFC8C39614159F /* Pods-Runner.profile.xcconfig */,
DB8991B7B046D94B2E68CEAD /* Pods-Runner.debug.xcconfig */,
EF8A0739582463E296AD6CB1 /* Pods-Runner.release.xcconfig */,
08F42BD28C1585A831B4FDA2 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -139,14 +139,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
854A11C1BE2493D5A6BD85DB /* [CP] Check Pods Manifest.lock */,
7BEA526A4A0DFAAC4945EC09 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
FDE6A3C9913AC5840FF42544 /* [CP] Embed Pods Frameworks */,
8DB6578C615972DBF2DFAA0D /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -168,7 +168,7 @@
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 5LSCTACHT8;
DevelopmentTeam = RCH2VG82SH;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
@@ -221,7 +221,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
854A11C1BE2493D5A6BD85DB /* [CP] Check Pods Manifest.lock */ = {
7BEA526A4A0DFAAC4945EC09 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -243,41 +243,41 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
8DB6578C615972DBF2DFAA0D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework",
);
name = "Run Script";
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
FDE6A3C9913AC5840FF42544 /* [CP] Embed Pods Frameworks */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework",
);
name = "[CP] Embed Pods Frameworks";
name = "Run Script";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */

@@ -372,7 +372,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -510,7 +510,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -541,7 +541,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",


+ 39
- 69
example/lib/main.dart Vedi File

@@ -6,11 +6,6 @@ import 'package:qr_code_scanner/qr_code_scanner.dart';

void main() => runApp(MaterialApp(home: QRViewExample()));

const flashOn = 'FLASH ON';
const flashOff = 'FLASH OFF';
const frontCamera = 'FRONT CAMERA';
const backCamera = 'BACK CAMERA';

class QRViewExample extends StatefulWidget {
const QRViewExample({
Key key,
@@ -22,8 +17,6 @@ class QRViewExample extends StatefulWidget {

class _QRViewExampleState extends State<QRViewExample> {
Barcode result;
var flashState = flashOn;
var cameraState = frontCamera;
QRViewController controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');

@@ -64,44 +57,33 @@ class _QRViewExampleState extends State<QRViewExample> {
Container(
margin: EdgeInsets.all(8),
child: RaisedButton(
onPressed: () {
if (controller != null) {
controller.toggleFlash();
if (_isFlashOn(flashState)) {
setState(() {
flashState = flashOff;
});
} else {
setState(() {
flashState = flashOn;
});
}
}
},
child:
Text(flashState, style: TextStyle(fontSize: 20)),
),
onPressed: () => setState(() {
controller?.toggleFlash();
}),
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: EdgeInsets.all(8),
child: RaisedButton(
onPressed: () {
if (controller != null) {
controller.flipCamera();
if (_isBackCamera(cameraState)) {
setState(() {
cameraState = frontCamera;
});
} else {
setState(() {
cameraState = backCamera;
});
}
}
},
child:
Text(cameraState, style: TextStyle(fontSize: 20)),
),
onPressed: () => setState(() {
controller?.flipCamera();
}),
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data)}');
} else {
return Text('loading');
}
},
)),
)
],
),
@@ -138,14 +120,6 @@ class _QRViewExampleState extends State<QRViewExample> {
);
}

bool _isFlashOn(String current) {
return flashOn == current;
}

bool _isBackCamera(String current) {
return backCamera == current;
}

Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 ||
@@ -154,29 +128,25 @@ class _QRViewExampleState extends State<QRViewExample> {
: 300.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return NotificationListener<SizeChangedLayoutNotification>(
onNotification: (notification) {
Future.microtask(
() => controller?.updateDimensions(qrKey, scanArea: scanArea));
return false;
},
child: SizeChangedLayoutNotifier(
key: const Key('qr-size-notifier'),
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea,
),
)));
return QRView(
key: qrKey,
cameraFacing: CameraFacing.front,
onQRViewCreated: _onQRViewCreated,
formatsAllowed: [BarcodeFormat.qrcode],
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea,
),
);
}

void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
setState(() {
result = scanData;


+ 1
- 1
example/pubspec.yaml Vedi File

@@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_qr plugin.
publish_to: 'none'

environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"

dependencies:
flutter:


+ 160
- 58
ios/Classes/QRView.swift Vedi File

@@ -13,75 +13,56 @@ public class QRView:NSObject,FlutterPlatformView {
var scanner: MTBBarcodeScanner?
var registrar: FlutterPluginRegistrar
var channel: FlutterMethodChannel
var cameraFacing: MTBCamera
public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){
var QRCodeTypes = [
0: AVMetadataObject.ObjectType.aztec,
2: AVMetadataObject.ObjectType.code39,
3: AVMetadataObject.ObjectType.code93,
4: AVMetadataObject.ObjectType.code128,
5: AVMetadataObject.ObjectType.dataMatrix,
6: AVMetadataObject.ObjectType.ean8,
7: AVMetadataObject.ObjectType.ean13,
8: AVMetadataObject.ObjectType.interleaved2of5,
10: AVMetadataObject.ObjectType.pdf417,
11: AVMetadataObject.ObjectType.qr,
15: AVMetadataObject.ObjectType.upce
]
public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){
self.registrar = registrar
previewView = UIView(frame: frame)
cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back
channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger())
}
func isCameraAvailable(success: Bool) -> Void {
if success {
do {
try scanner?.startScanning(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]
self?.channel.invokeMethod("onRecognizeQR", arguments: result)
}
}
})
} catch {
NSLog("Unable to start scanning")
}
} else {
UIAlertView(title: "Scanning Unavailable", message: "This app does not have permission to access the camera", delegate: nil, cancelButtonTitle: nil, otherButtonTitles: "Ok").show()
}
deinit {
scanner?.stopScanning()
}
public func view() -> UIView {
channel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
[weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch(call.method){
case "setDimensions":
let arguments = call.arguments as! Dictionary<String, Double>
self?.setDimensions(width: arguments["width"] ?? 0, height: arguments["height"] ?? 0, scanArea: arguments["scanArea"] ?? 0)
case "startScan":
self?.startScan(call.arguments as! Array<Int>, result)
case "flipCamera":
self?.flipCamera()
self?.flipCamera(result)
case "toggleFlash":
self?.toggleFlash()
self?.toggleFlash(result)
case "pauseCamera":
self?.pauseCamera()
self?.pauseCamera(result)
case "resumeCamera":
self?.resumeCamera()
self?.resumeCamera(result)
case "getCameraInfo":
self?.getCameraInfo(result)
case "getFlashInfo":
self?.getFlashInfo(result)
case "getSystemFeatures":
self?.getSystemFeatures(result)
default:
result(FlutterMethodNotImplemented)
return
@@ -106,41 +87,162 @@ public class QRView:NSObject,FlutterPlatformView {
self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea)
}
}
}
}
func startScan(_ arguments: Array<Int>, _ result: @escaping FlutterResult) -> Void {
scanner = MTBBarcodeScanner(previewView: previewView)
var allowedBarcodeTypes: Array<AVMetadataObject.ObjectType> = []
arguments.forEach { arg in
allowedBarcodeTypes.append( QRCodeTypes[arg]!)
}


MTBBarcodeScanner.requestCameraPermission(success: isCameraAvailable)
MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in
if permissionGranted {
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)
}
}
}
})
} catch {
let error = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: nil)
result(error)
}
} else {
let error = FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)
result(error)
}
})
}
func stopScan(){
if let sc: MTBBarcodeScanner = scanner {
if sc.isScanning() {
sc.stopScanning()
}
}
}
func getCameraInfo(_ result: @escaping FlutterResult) -> Void {
if let sc: MTBBarcodeScanner = scanner {
result(sc.camera.rawValue)
} else {
let error = FlutterError(code: "cameraInformationError", message: "Could not get camera information", details: nil)
result(error)
}
}
func flipCamera(){
func flipCamera(_ result: @escaping FlutterResult){
if let sc: MTBBarcodeScanner = scanner {
if sc.hasOppositeCamera() {
sc.flipCamera()
}
return result(sc.camera.rawValue)
}
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
}
func getFlashInfo(_ result: @escaping FlutterResult) -> Void {
if let sc: MTBBarcodeScanner = scanner {
result(sc.torchMode.rawValue != 0)
} else {
let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil)
result(error)
}
}
func toggleFlash(){
func toggleFlash(_ result: @escaping FlutterResult){
if let sc: MTBBarcodeScanner = 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() {
func pauseCamera(_ result: @escaping FlutterResult) {
if let sc: MTBBarcodeScanner = scanner {
if sc.isScanning() {
sc.freezeCapture()
}
return result(true)
}
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
}
func resumeCamera() {
func resumeCamera(_ result: @escaping FlutterResult) {
if let sc: MTBBarcodeScanner = 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 {
if let sc: MTBBarcodeScanner = scanner {
var hasBackCameraVar = false
var hasFrontCameraVar = false
let camera = sc.camera

if(camera == MTBCamera(rawValue: 0)){
hasBackCameraVar = true
if sc.hasOppositeCamera() {
hasFrontCameraVar = true
}
}else{
hasFrontCameraVar = true
if sc.hasOppositeCamera() {
hasBackCameraVar = true
}
}
return result([
"hasFrontCamera": hasFrontCameraVar,
"hasBackCamera": hasBackCameraVar,
"hasFlash": sc.hasTorch(),
"activeCamera": camera.rawValue
])
}
return result(FlutterError(code: "404", message: nil, details: nil))
}
}

}

+ 2
- 2
ios/Classes/QRViewFactory.swift Vedi File

@@ -17,8 +17,8 @@ public class QRViewFactory: NSObject, FlutterPlatformViewFactory {
}
public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
let dictionary = args as! Dictionary<String, Double>
return QRView(withFrame: CGRect(x: 0, y: 0, width: dictionary["width"] ?? 0, height: dictionary["height"] ?? 0), withRegistrar: registrar!,withId: viewId)
let params = args as! Dictionary<String, Double>
return QRView(withFrame: frame, withRegistrar: registrar!,withId: viewId, params: params)
}
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {


+ 5
- 0
lib/qr_code_scanner.dart Vedi File

@@ -1,2 +1,7 @@
export 'src/qr_code_scanner.dart';
export 'src/qr_scanner_overlay_shape.dart';
export 'src/types/barcode.dart';
export 'src/types/barcode_format.dart';
export 'src/types/camera.dart';
export 'src/types/camera_exception.dart';
export 'src/types/features.dart';

+ 196
- 151
lib/src/qr_code_scanner.dart Vedi File

@@ -3,138 +3,107 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';

typedef QRViewCreatedCallback = void Function(QRViewController);

enum BarcodeFormat {
/// Aztec 2D barcode format.
aztec,

/// CODABAR 1D format.
codabar,

/// Code 39 1D format.
code39,

/// Code 93 1D format.
code93,

/// Code 128 1D format.
code128,

/// Data Matrix 2D barcode format.
dataMatrix,

/// EAN-8 1D format.
ean8,

/// EAN-13 1D format.
ean13,

/// ITF (Interleaved Two of Five) 1D format.
itf,

/// MaxiCode 2D barcode format.
maxicode,

/// PDF417 format.
pdf417,

/// QR Code 2D barcode format.
qrcode,

/// RSS 14
rss14,

/// RSS EXPANDED
rssExpanded,

/// UPC-A 1D format.
upcA,
import 'qr_scanner_overlay_shape.dart';
import 'types/barcode.dart';
import 'types/barcode_format.dart';
import 'types/camera.dart';
import 'types/camera_exception.dart';
import 'types/features.dart';

/// UPC-E 1D format.
upcE,

/// UPC/EAN extension format. Not a stand-alone format.
upcEanExtension
}

const _formatNames = <String, BarcodeFormat>{
'AZTEC': BarcodeFormat.aztec,
'CODABAR': BarcodeFormat.codabar,
'CODE_39': BarcodeFormat.code39,
'CODE_93': BarcodeFormat.code93,
'CODE_128': BarcodeFormat.code128,
'DATA_MATRIX': BarcodeFormat.dataMatrix,
'EAN_8': BarcodeFormat.ean8,
'EAN_13': BarcodeFormat.ean13,
'ITF': BarcodeFormat.itf,
'MAXICODE': BarcodeFormat.maxicode,
'PDF_417': BarcodeFormat.pdf417,
'QR_CODE': BarcodeFormat.qrcode,
'RSS_14': BarcodeFormat.rss14,
'RSS_EXPANDED': BarcodeFormat.rssExpanded,
'UPC_A': BarcodeFormat.upcA,
'UPC_E': BarcodeFormat.upcE,
'UPC_EAN_EXTENSION': BarcodeFormat.upcEanExtension,
};

class Barcode {
Barcode(this.code, this.format, this.rawBytes);

final String code;
final BarcodeFormat format;

/// Raw bytes are only supported by Android.
final List<int> rawBytes;
}
typedef QRViewCreatedCallback = void Function(QRViewController);
typedef PermissionSetCallback = void Function(QRViewController, bool);

/// The [QRView] is the view where the camera
/// and the barcode scanner gets displayed.
class QRView extends StatefulWidget {
const QRView({
@required Key key,
@required this.onQRViewCreated,
this.overlay,
this.overlayMargin = EdgeInsets.zero,
this.cameraFacing = CameraFacing.back,
this.onPermissionSet,
this.formatsAllowed,
}) : assert(key != null),
assert(onQRViewCreated != null),
super(key: key);

/// [onQRViewCreated] gets called when the view is created
final QRViewCreatedCallback onQRViewCreated;

/// Use [overlay] to provide an overlay for the view.
/// This can be used to create a certain scan area.
final ShapeBorder overlay;

/// Use [overlayMargin] to provide a margin to [overlay]
final EdgeInsetsGeometry overlayMargin;

/// Set which camera to use on startup.
///
/// [cameraFacing] can either be CameraFacing.front or CameraFacing.back.
/// Defaults to CameraFacing.back
final CameraFacing cameraFacing;

/// Calls the provided [onPermissionSet] callback when the permission is set.
final PermissionSetCallback onPermissionSet;

/// Use [formatsAllowed] to specify which formats needs to be scanned.
final List<BarcodeFormat> formatsAllowed;

@override
State<StatefulWidget> createState() => _QRViewState();
}

class _QRViewState extends State<QRView> {
var _channel;

@override
Widget build(BuildContext context) {
return NotificationListener(
onNotification: onNotification,
child: SizeChangedLayoutNotifier(
child: (widget.overlay != null)
? _getPlatformQrViewWithOverlay()
: _getPlatformQrView(),
),
);
}

bool onNotification(notification) {
Future.microtask(() => {
QRViewController.updateDimensions(widget.key, _channel,
scanArea: widget.overlay != null
? (widget.overlay as QrScannerOverlayShape).cutOutSize
: 0.0)
});
return false;
}

Widget _getPlatformQrViewWithOverlay() {
return Stack(
children: [
_getPlatformQrView(widget.key),
if (widget.overlay != null)
Container(
padding: widget.overlayMargin,
decoration: ShapeDecoration(
shape: widget.overlay,
),
)
else
Container(),
_getPlatformQrView(),
Container(
padding: widget.overlayMargin,
decoration: ShapeDecoration(
shape: widget.overlay,
),
)
],
);
}

Widget _getPlatformQrView(GlobalKey key) {
Widget _getPlatformQrView() {
Widget _platformQrView;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
_platformQrView = AndroidView(
viewType: 'net.touchcapture.qr.flutterqr/qrview',
onPlatformViewCreated: _onPlatformViewCreated,
creationParams:
_QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(),
creationParamsCodec: StandardMessageCodec(),
);
break;
case TargetPlatform.iOS:
@@ -142,8 +111,7 @@ class _QRViewState extends State<QRView> {
viewType: 'net.touchcapture.qr.flutterqr/qrview',
onPlatformViewCreated: _onPlatformViewCreated,
creationParams:
_CreationParams.fromWidget(MediaQuery.of(context).size.width, 400)
.toMap(),
_QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(),
creationParamsCodec: StandardMessageCodec(),
);
break;
@@ -155,101 +123,178 @@ class _QRViewState extends State<QRView> {
}

void _onPlatformViewCreated(int id) {
if (widget.onQRViewCreated == null) {
return;
}

// We pass the cutout size so that the scanner respects the scan area.
var cutOutSize = 0.0;
if (widget.overlay != null) {
cutOutSize = (widget.overlay as QrScannerOverlayShape).cutOutSize;
}

widget.onQRViewCreated(QRViewController._(id, widget.key, cutOutSize));
}
}
_channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id');

class _CreationParams {
_CreationParams({this.width, this.height});
// Start scan after creation of the view
final controller = QRViewController._(
_channel, widget.key, cutOutSize, widget.onPermissionSet)
.._startScan(widget.key, cutOutSize, widget.formatsAllowed);

static _CreationParams fromWidget(double width, double height) {
return _CreationParams(
width: width,
height: height,
);
// Initialize the controller for controlling the QRView
if (widget.onQRViewCreated != null) {
widget.onQRViewCreated(controller);
}
}
}

final double width;
final double height;
class _QrCameraSettings {
_QrCameraSettings({
this.cameraFacing,
});

final CameraFacing cameraFacing;

Map<String, dynamic> toMap() {
return <String, dynamic>{
'width': width,
'height': height,
'cameraFacing': cameraFacing.index,
};
}
}

class QRViewController {
QRViewController._(int id, GlobalKey qrKey, double scanArea)
: _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') {
updateDimensions(qrKey, scanArea: scanArea);
_channel.setMethodCallHandler(
(call) async {
switch (call.method) {
case scanMethodCall:
if (call.arguments != null) {
final args = call.arguments as Map;
final code = args['code'] as String;
final rawType = args['type'] as String;
// Raw bytes are only supported by Android.
final rawBytes = args['rawBytes'] as List<int>;
final format = _formatNames[rawType];
if (format != null) {
final barcode = Barcode(code, format, rawBytes);
_scanUpdateController.sink.add(barcode);
} else {
throw Exception('Unexpected barcode type $rawType');
}
QRViewController._(MethodChannel channel, GlobalKey qrKey, double scanArea,
PermissionSetCallback onPermissionSet)
: _channel = channel {
_channel.setMethodCallHandler((call) async {
switch (call.method) {
case 'onRecognizeQR':
if (call.arguments != null) {
final args = call.arguments as Map;
final code = args['code'] as String;
final rawType = args['type'] as String;
// Raw bytes are only supported by Android.
final rawBytes = args['rawBytes'] as List<int>;
final format = BarcodeTypesExtension.fromString(rawType);
if (format != null) {
final barcode = Barcode(code, format, rawBytes);
_scanUpdateController.sink.add(barcode);
} else {
throw Exception('Unexpected barcode type $rawType');
}
}
},
);
}
break;
case 'onPermissionSet':
await getSystemFeatures(); // if we have no permission all features will not be avaible
if (call.arguments != null) {
if (call.arguments as bool) {
_hasPermissions = true;
} else {
_hasPermissions = false;
}
if (onPermissionSet != null) {
onPermissionSet(this, call.arguments as bool);
}
}
break;
}
});
}

static const scanMethodCall = 'onRecognizeQR';

final MethodChannel _channel;

final StreamController<Barcode> _scanUpdateController =
StreamController<Barcode>();

Stream<Barcode> get scannedDataStream => _scanUpdateController.stream;

void flipCamera() {
_channel.invokeMethod('flipCamera');
SystemFeatures _features;
bool _hasPermissions;

SystemFeatures get systemFeatures => _features;
bool get hasPermissions => _hasPermissions;

/// Starts the barcode scanner
Future<void> _startScan(GlobalKey key, double cutOutSize,
List<BarcodeFormat> barcodeFormats) async {
// We need to update the dimension before the scan is started.
QRViewController.updateDimensions(key, _channel, scanArea: cutOutSize);
return _channel.invokeMethod(
'startScan', barcodeFormats?.map((e) => e.asInt())?.toList() ?? []);
}

void toggleFlash() {
_channel.invokeMethod('toggleFlash');
/// Gets information about which camera is active.
Future<CameraFacing> getCameraInfo() async {
try {
return CameraFacing
.values[await _channel.invokeMethod('getCameraInfo') as int];
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Flips the camera between available modes
Future<CameraFacing> flipCamera() async {
try {
return CameraFacing
.values[await _channel.invokeMethod('flipCamera') as int];
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

void pauseCamera() {
_channel.invokeMethod('pauseCamera');
/// Get flashlight status
Future<bool> getFlashStatus() async {
try {
return await _channel.invokeMethod('getFlashInfo');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Toggles the flashlight between available modes
Future<void> toggleFlash() async {
try {
await _channel.invokeMethod('toggleFlash') as bool;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

void resumeCamera() {
_channel.invokeMethod('resumeCamera');
/// Pauses barcode scanning
Future<void> pauseCamera() async {
try {
await _channel.invokeMethod('pauseCamera');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Resumes barcode scanning
Future<void> resumeCamera() async {
try {
await _channel.invokeMethod('resumeCamera');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Returns which features are available on device.
Future<SystemFeatures> getSystemFeatures() async {
try {
var features =
await _channel.invokeMapMethod<String, dynamic>('getSystemFeatures');
return SystemFeatures.fromJson(features);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Disposes the barcode stream.
void dispose() {
_scanUpdateController.close();
}

void updateDimensions(GlobalKey key, {double scanArea}) {
/// Updates the view dimensions for iOS.
static void updateDimensions(GlobalKey key, MethodChannel channel,
{double scanArea}) {
if (defaultTargetPlatform == TargetPlatform.iOS) {
final RenderBox renderBox = key.currentContext.findRenderObject();
_channel.invokeMethod('setDimensions', {
channel.invokeMethod('setDimensions', {
'width': renderBox.size.width,
'height': renderBox.size.height,
'scanArea': scanArea ?? 0


+ 16
- 0
lib/src/types/barcode.dart Vedi File

@@ -0,0 +1,16 @@
import 'barcode_format.dart';

/// The [Barcode] object holds information about the barcode or qr code.
///
/// [code] is the content of the barcode.
/// [format] displays which type the code is.
/// Only for Android, [rawBytes] gives a list of bytes of the result.
class Barcode {
Barcode(this.code, this.format, this.rawBytes);

final String code;
final BarcodeFormat format;

/// Raw bytes are only supported by Android.
final List<int> rawBytes;
}

+ 174
- 0
lib/src/types/barcode_format.dart Vedi File

@@ -0,0 +1,174 @@
enum BarcodeFormat {
/// Aztec 2D barcode format.
aztec,

/// CODABAR 1D format.
codabar,

/// Code 39 1D format.
code39,

/// Code 93 1D format.
code93,

/// Code 128 1D format.
code128,

/// Data Matrix 2D barcode format.
dataMatrix,

/// EAN-8 1D format.
ean8,

/// EAN-13 1D format.
ean13,

/// ITF (Interleaved Two of Five) 1D format.
itf,

/// MaxiCode 2D barcode format.
maxicode,

/// PDF417 format.
pdf417,

/// QR Code 2D barcode format.
qrcode,

/// RSS 14
rss14,

/// RSS EXPANDED
rssExpanded,

/// UPC-A 1D format.
upcA,

/// UPC-E 1D format.
upcE,

/// UPC/EAN extension format. Not a stand-alone format.
upcEanExtension
}

extension BarcodeTypesExtension on BarcodeFormat {
int asInt() {
return index;
}

static BarcodeFormat fromString(String format) {
switch (format) {
case 'AZTEC':
return BarcodeFormat.aztec;
break;
case 'CODABAR':
return BarcodeFormat.codabar;
break;
case 'CODE_39':
return BarcodeFormat.code39;
break;
case 'CODE_93':
return BarcodeFormat.code93;
break;
case 'CODE_128':
return BarcodeFormat.code128;
break;
case 'DATA_MATRIX':
return BarcodeFormat.dataMatrix;
break;
case 'EAN_8':
return BarcodeFormat.ean8;
break;
case 'EAN_13':
return BarcodeFormat.ean13;
break;
case 'ITF':
return BarcodeFormat.itf;
break;
case 'MAXICODE':
return BarcodeFormat.maxicode;
break;
case 'PDF_417':
return BarcodeFormat.pdf417;
break;
case 'QR_CODE':
return BarcodeFormat.qrcode;
break;
case 'RSS14':
return BarcodeFormat.rss14;
break;
case 'RSS_EXPANDED':
return BarcodeFormat.rssExpanded;
break;
case 'UPC_A':
return BarcodeFormat.upcA;
break;
case 'UPC_E':
return BarcodeFormat.upcE;
break;
case 'UPC_EAN_EXTENSION':
return BarcodeFormat.upcEanExtension;
break;
default:
return null;
}
}

String get formatName {
switch (this) {
case BarcodeFormat.aztec:
return 'AZTEC';
break;
case BarcodeFormat.codabar:
return 'CODABAR';
break;
case BarcodeFormat.code39:
return 'CODE_39';
break;
case BarcodeFormat.code93:
return 'CODE_93';
break;
case BarcodeFormat.code128:
return 'CODE_128';
break;
case BarcodeFormat.dataMatrix:
return 'DATA_MATRIX';
break;
case BarcodeFormat.ean8:
return 'EAN_8';
break;
case BarcodeFormat.ean13:
return 'EAN_13';
break;
case BarcodeFormat.itf:
return 'ITF';
break;
case BarcodeFormat.maxicode:
return 'MAXICODE';
break;
case BarcodeFormat.pdf417:
return 'PDF_417';
break;
case BarcodeFormat.qrcode:
return 'QR_CODE';
break;
case BarcodeFormat.rss14:
return 'RSS14';
break;
case BarcodeFormat.rssExpanded:
return 'RSS_EXPANDED';
break;
case BarcodeFormat.upcA:
return 'UPC_A';
break;
case BarcodeFormat.upcE:
return 'UPC_E';
break;
case BarcodeFormat.upcEanExtension:
return 'UPC_EAN_EXTENSION';
break;
default:
return 'NOT_VALID';
}
}
}

+ 7
- 0
lib/src/types/camera.dart Vedi File

@@ -0,0 +1,7 @@
enum CameraFacing {
/// Shows back facing camera.
back,

/// Shows front facing camera.
front
}

+ 14
- 0
lib/src/types/camera_exception.dart Vedi File

@@ -0,0 +1,14 @@
/// This is thrown when the plugin reports an error.
class CameraException implements Exception {
/// Creates a new camera exception with the given error code and description.
CameraException(this.code, this.description);

/// Error code.
String code;

/// Textual description of the error.
String description;

@override
String toString() => 'CameraException($code, $description)';
}

+ 13
- 0
lib/src/types/features.dart Vedi File

@@ -0,0 +1,13 @@
class SystemFeatures {
SystemFeatures(this.hasFlash, this.hasBackCamera, this.hasFrontCamera);

factory SystemFeatures.fromJson(Map<String, dynamic> features) =>
SystemFeatures(
features['hasFlash'] ?? false,
features['hasBackCamera'] ?? false,
features['hasFrontCamera'] ?? false);

final bool hasFlash;
final bool hasFrontCamera;
final bool hasBackCamera;
}

+ 1
- 1
pubspec.yaml Vedi File

@@ -5,7 +5,7 @@ homepage: https://juliuscanute.com
repository: https://github.com/juliuscanute/qr_code_scanner

environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
flutter: ^1.10.0

dependencies:


Caricamento…
Annulla
Salva