Julian Steenbakker
Committed by GitHub

Merge pull request #21 from juliansteenbakker/bug/start-stop-crash

bugfix: Fixed crash on multiple start() or stop() calls.
include: package:flutter_lints/flutter.yaml
linter:
rules:
unawaited_futures: true
\ No newline at end of file
... ...
... ... @@ -38,8 +38,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
private var camera: Camera? = null
private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null
@AnalyzeMode
private var analyzeMode: Int = AnalyzeMode.NONE
// @AnalyzeMode
// private var analyzeMode: Int = AnalyzeMode.NONE
@ExperimentalGetImage
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) {
... ... @@ -47,8 +47,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
"state" -> checkPermission(result)
"request" -> requestPermission(result)
"start" -> start(call, result)
"torch" -> switchTorch(call, result)
"analyze" -> switchAnalyzeMode(call, result)
"torch" -> toggleTorch(call, result)
// "analyze" -> switchAnalyzeMode(call, result)
"stop" -> stop(result)
else -> result.notImplemented()
}
... ... @@ -92,8 +92,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
@ExperimentalGetImage
val analyzer = ImageAnalysis.Analyzer { imageProxy -> // YUV_420_888 format
when (analyzeMode) {
AnalyzeMode.BARCODE -> {
// when (analyzeMode) {
// AnalyzeMode.BARCODE -> {
val mediaImage = imageProxy.image ?: return@Analyzer
val inputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
... ... @@ -106,9 +106,9 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
}
.addOnFailureListener { e -> Log.e(TAG, e.message, e) }
.addOnCompleteListener { imageProxy.close() }
}
else -> imageProxy.close()
}
// }
// else -> imageProxy.close()
// }
}
... ... @@ -116,6 +116,10 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
@ExperimentalGetImage
private fun start(call: MethodCall, result: MethodChannel.Result) {
if (camera != null) {
result.error(TAG, "Called start() while already started!", null)
return
}
val facing: Int = call.argument<Int>("facing") ?: 0
val ratio: Int? = call.argument<Int>("ratio")
... ... @@ -186,24 +190,32 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
}, executor)
}
private fun switchTorch(call: MethodCall, result: MethodChannel.Result) {
val state = call.arguments == 1
camera!!.cameraControl.enableTorch(state)
result.success(null)
private fun toggleTorch(call: MethodCall, result: MethodChannel.Result) {
if (camera == null) {
result.error(TAG,"Called toggleTorch() while stopped!", null)
return
}
private fun switchAnalyzeMode(call: MethodCall, result: MethodChannel.Result) {
analyzeMode = call.arguments as Int
camera!!.cameraControl.enableTorch(call.arguments == 1)
result.success(null)
}
// private fun switchAnalyzeMode(call: MethodCall, result: MethodChannel.Result) {
// analyzeMode = call.arguments as Int
// result.success(null)
// }
private fun stop(result: MethodChannel.Result) {
if (camera == null) {
result.error(TAG,"Called stop() while already stopped!", null)
return
}
val owner = activity as LifecycleOwner
camera!!.cameraInfo.torchState.removeObservers(owner)
cameraProvider!!.unbindAll()
textureEntry!!.release()
analyzeMode = AnalyzeMode.NONE
// analyzeMode = AnalyzeMode.NONE
camera = null
textureEntry = null
cameraProvider = null
... ...
platform :osx, '10.11'
platform :osx, '10.13'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
... ...
... ... @@ -26,7 +26,7 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
5225F51353DA345E2811B6A4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */; };
5B9BD2ADBC68B74D80B57DF1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
... ... @@ -67,12 +67,12 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3CEE8DB43A84811F33EB0202 /* 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>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
CB0901144E09E7D7CA20584F /* 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>"; };
D522F9F6F348C5944077606B /* 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>"; };
F63009B5E287A1C82F9D7D2F /* 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>"; };
A1CBC07680A8ED396DBB68C0 /* 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>"; };
CAD760C57A57D903AB03B47A /* 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>"; };
EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
... ... @@ -80,19 +80,27 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5225F51353DA345E2811B6A4 /* Pods_Runner.framework in Frameworks */,
5B9BD2ADBC68B74D80B57DF1 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
18927D60C719EB75FC0A6633 /* Frameworks */ = {
isa = PBXGroup;
children = (
EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
20F8C9AA20C2A495C125E194 /* Pods */ = {
isa = PBXGroup;
children = (
CB0901144E09E7D7CA20584F /* Pods-Runner.debug.xcconfig */,
D522F9F6F348C5944077606B /* Pods-Runner.release.xcconfig */,
F63009B5E287A1C82F9D7D2F /* Pods-Runner.profile.xcconfig */,
CAD760C57A57D903AB03B47A /* Pods-Runner.debug.xcconfig */,
A1CBC07680A8ED396DBB68C0 /* Pods-Runner.release.xcconfig */,
3CEE8DB43A84811F33EB0202 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
... ... @@ -115,7 +123,7 @@
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
20F8C9AA20C2A495C125E194 /* Pods */,
3539353E79638640B4999C09 /* Frameworks */,
18927D60C719EB75FC0A6633 /* Frameworks */,
);
sourceTree = "<group>";
};
... ... @@ -162,14 +170,6 @@
path = Runner;
sourceTree = "<group>";
};
3539353E79638640B4999C09 /* Frameworks */ = {
isa = PBXGroup;
children = (
65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
... ... @@ -177,13 +177,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
696298230BDAD783AEC51C81 /* [CP] Check Pods Manifest.lock */,
20903D1E9D9F08576541FFD7 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
8A90D2BC4083C5ACCEEBF32B /* [CP] Embed Pods Frameworks */,
DF45614760BB9B24F49B2055 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
... ... @@ -253,7 +253,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
20903D1E9D9F08576541FFD7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
... ... @@ -261,58 +261,58 @@
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
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;
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
696298230BDAD783AEC51C81 /* [CP] Check Pods Manifest.lock */ = {
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
Flutter/ephemeral/tripwire,
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
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;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
8A90D2BC4083C5ACCEEBF32B /* [CP] Embed Pods Frameworks */ = {
DF45614760BB9B24F49B2055 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
... ...
... ... @@ -23,7 +23,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
var latestBuffer: CVImageBuffer!
var analyzeMode: Int = 0
// var analyzeMode: Int = 0
var analyzing: Bool = false
var position = AVCaptureDevice.Position.back
... ... @@ -53,9 +53,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
case "start":
start(call, result)
case "torch":
switchTorch(call, result)
case "analyze":
switchAnalyzeMode(call, result)
toggleTorch(call, result)
// case "analyze":
// switchAnalyzeMode(call, result)
case "stop":
stop(result)
default:
... ... @@ -89,10 +89,10 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
registry.textureFrameAvailable(textureId)
switch analyzeMode {
case 1: // barcode
// switch analyzeMode {
// case 1: // barcode
if analyzing {
break
return
}
analyzing = true
let buffer = CMSampleBufferGetImageBuffer(sampleBuffer)
... ... @@ -112,9 +112,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
}
analyzing = false
}
default: // none
break
}
// default: // none
// break
// }
}
func imageOrientation(
... ... @@ -154,6 +154,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
}
func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
if (device != nil) {
result(FlutterError(code: "MobileScanner",
message: "Called start() while already started!",
details: nil))
return
}
textureId = registry.register(self)
captureSession = AVCaptureSession()
... ... @@ -173,6 +180,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first
}
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "No camera found or failed to open camera!",
details: nil))
return
}
// Enable the torch if parameter is set and torch is available
if (device.hasTorch && device.isTorchAvailable) {
do {
... ... @@ -219,7 +233,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
result(answer)
}
func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "Called toggleTorch() while stopped!",
details: nil))
return
}
do {
try device.lockForConfiguration()
device.torchMode = call.arguments as! Int == 1 ? .on : .off
... ... @@ -230,12 +250,18 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
}
}
func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
analyzeMode = call.arguments as! Int
result(nil)
}
// func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
// analyzeMode = call.arguments as! Int
// result(nil)
// }
func stop(_ result: FlutterResult) {
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "Called stop() while already stopped!",
details: nil))
return
}
captureSession.stopRunning()
for input in captureSession.inputs {
captureSession.removeInput(input)
... ... @@ -246,7 +272,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode))
registry.unregisterTexture(textureId)
analyzeMode = 0
// analyzeMode = 0
latestBuffer = nil
captureSession = nil
device = nil
... ...
... ... @@ -27,7 +27,7 @@ enum TorchState {
on,
}
enum AnalyzeMode { none, barcode }
// enum AnalyzeMode { none, barcode }
class MobileScannerController {
MethodChannel methodChannel =
... ... @@ -62,8 +62,8 @@ class MobileScannerController {
// Sets analyze mode and barcode stream
barcodesController = StreamController.broadcast(
onListen: () => setAnalyzeMode(AnalyzeMode.barcode.index),
onCancel: () => setAnalyzeMode(AnalyzeMode.none.index),
// onListen: () => setAnalyzeMode(AnalyzeMode.barcode.index),
// onCancel: () => setAnalyzeMode(AnalyzeMode.none.index),
);
start();
... ... @@ -94,12 +94,13 @@ class MobileScannerController {
}
}
void setAnalyzeMode(int mode) {
if (hashCode != _controllerHashcode) {
return;
}
methodChannel.invokeMethod('analyze', mode);
}
// TODO: Add more analyzers like text analyzer
// void setAnalyzeMode(int mode) {
// if (hashCode != _controllerHashcode) {
// return;
// }
// methodChannel.invokeMethod('analyze', mode);
// }
// List<BarcodeFormats>? formats = _defaultBarcodeFormats,
/// Start barcode scanning. This will first check if the required permissions
... ... @@ -107,7 +108,7 @@ class MobileScannerController {
Future<void> start() async {
ensure('startAsync');
setAnalyzeMode(AnalyzeMode.barcode.index);
// setAnalyzeMode(AnalyzeMode.barcode.index);
// Check authorization status
MobileScannerState state =
MobileScannerState.values[await methodChannel.invokeMethod('state')];
... ... @@ -132,8 +133,15 @@ class MobileScannerController {
if (torchEnabled != null) arguments['torch'] = torchEnabled;
// Start the camera with arguments
final Map<String, dynamic>? startResult = await methodChannel
.invokeMapMethod<String, dynamic>('start', arguments);
Map<String, dynamic>? startResult = {};
try {
startResult = await methodChannel.invokeMapMethod<String, dynamic>(
'start', arguments);
} on PlatformException catch (error) {
debugPrint('${error.code}: ${error.message}');
// setAnalyzeMode(AnalyzeMode.none.index);
return;
}
if (startResult == null) {
throw PlatformException(code: 'INITIALIZATION ERROR');
... ... @@ -146,17 +154,32 @@ class MobileScannerController {
hasTorch: hasTorch);
}
Future<void> stop() async => await methodChannel.invokeMethod('stop');
Future<void> stop() async {
try {
await methodChannel.invokeMethod('stop');
} on PlatformException catch (error) {
debugPrint('${error.code}: ${error.message}');
}
}
/// Switches the torch on or off.
///
/// Only works if torch is available.
void toggleTorch() {
Future<void> toggleTorch() async {
ensure('toggleTorch');
if (!hasTorch) return;
if (!hasTorch) {
debugPrint('Device has no torch/flash.');
return;
}
TorchState state =
torchState.value == TorchState.off ? TorchState.on : TorchState.off;
methodChannel.invokeMethod('torch', state.index);
try {
await methodChannel.invokeMethod('torch', state.index);
} on PlatformException catch (error) {
debugPrint('${error.code}: ${error.message}');
}
}
/// Switches the torch on or off.
... ... @@ -164,10 +187,16 @@ class MobileScannerController {
/// Only works if torch is available.
Future<void> switchCamera() async {
ensure('switchCamera');
await stop();
try {
await methodChannel.invokeMethod('stop');
} on PlatformException catch (error) {
debugPrint(
'${error.code}: camera is stopped! Please start before switching camera.');
return;
}
facing =
facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back;
start();
await start();
}
/// Disposes the controller and closes all listeners.
... ...
... ... @@ -22,7 +22,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
var latestBuffer: CVImageBuffer!
var analyzeMode: Int = 0
// var analyzeMode: Int = 0
var analyzing: Bool = false
var position = AVCaptureDevice.Position.back
... ... @@ -52,9 +52,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
case "start":
start(call, result)
case "torch":
switchTorch(call, result)
case "analyze":
switchAnalyzeMode(call, result)
toggleTorch(call, result)
// case "analyze":
// switchAnalyzeMode(call, result)
case "stop":
stop(result)
default:
... ... @@ -92,14 +92,14 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
registry.textureFrameAvailable(textureId)
switch analyzeMode {
case 1: // barcode
// switch analyzeMode {
// case 1: // barcode
// Limit the analyzer because the texture output will freeze otherwise
if i / 10 == 1 {
i = 0
} else {
break
return
}
let imageRequestHandler = VNImageRequestHandler(
cvPixelBuffer: latestBuffer,
... ... @@ -129,9 +129,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
print(error)
}
default: // none
break
}
// default: // none
// break
// }
}
func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
... ... @@ -159,6 +159,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
}
func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
if (device != nil) {
result(FlutterError(code: "MobileScanner",
message: "Called start() while already started!",
details: nil))
return
}
textureId = registry.register(self)
captureSession = AVCaptureSession()
... ... @@ -178,6 +185,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first
}
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "No camera found or failed to open camera!",
details: nil))
return
}
// Enable the torch if parameter is set and torch is available
if (device.hasTorch) {
do {
... ... @@ -222,7 +236,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
result(answer)
}
func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "Called toggleTorch() while stopped!",
details: nil))
return
}
do {
try device.lockForConfiguration()
device.torchMode = call.arguments as! Int == 1 ? .on : .off
... ... @@ -233,12 +253,18 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
}
}
func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
analyzeMode = call.arguments as! Int
result(nil)
}
// func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
// analyzeMode = call.arguments as! Int
// result(nil)
// }
func stop(_ result: FlutterResult) {
if (device == nil) {
result(FlutterError(code: "MobileScanner",
message: "Called stop() while already stopped!",
details: nil))
return
}
captureSession.stopRunning()
for input in captureSession.inputs {
captureSession.removeInput(input)
... ... @@ -249,7 +275,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode))
registry.unregisterTexture(textureId)
analyzeMode = 0
// analyzeMode = 0
latestBuffer = nil
captureSession = nil
device = nil
... ...