start method
Start scanning for barcodes.
The cameraDirection can be used to specify the camera direction.
If this is null, this defaults to the facing value.
The cameraLensType can be used to specify the camera lens type.
If this is null, this defaults to the lensType value.
Does nothing if the camera is already running. Upon calling this method, the necessary camera permission will be requested.
If the permission is denied on iOS, MacOS or Web, there is no way to request it again.
Implementation
Future<void> start({
CameraFacing? cameraDirection,
CameraLensType? cameraLensType,
}) async {
if (_isDisposed) {
throw MobileScannerException(
errorCode: MobileScannerErrorCode.controllerDisposed,
errorDetails: MobileScannerErrorDetails(
message: MobileScannerErrorCode.controllerDisposed.message,
),
);
}
// If start was called before the MobileScanner widget
// had a chance to call its initState method,
// wait for it to be called, using a timeout.
if (!_isAttachedCompleter.isCompleted) {
// The timeout is currently an arbitrary value,
// which should be long enough for the next frame
// to propagate any pending changes to the widget tree.
await _isAttachedCompleter.future
.timeout(const Duration(milliseconds: 500))
.catchError((Object error, StackTrace stackTrace) {
throw MobileScannerException(
errorCode: MobileScannerErrorCode.controllerNotAttached,
errorDetails: MobileScannerErrorDetails(
message: MobileScannerErrorCode.controllerNotAttached.message,
details: stackTrace.toString(),
),
);
});
// Abort if the controller was disposed
// while waiting for the widget to be attached.
if (_isDisposed) {
throw MobileScannerException(
errorCode: MobileScannerErrorCode.controllerDisposed,
errorDetails: MobileScannerErrorDetails(
message: MobileScannerErrorCode.controllerDisposed.message,
),
);
}
}
if (cameraDirection == CameraFacing.unknown) {
throw const MobileScannerException(
errorCode: MobileScannerErrorCode.genericError,
errorDetails: MobileScannerErrorDetails(
message: 'CameraFacing.unknown is not a valid camera direction.',
),
);
}
// Do nothing if the camera is already running.
if (value.isRunning) {
return;
}
if (value.isStarting) {
throw MobileScannerException(
errorCode: MobileScannerErrorCode.controllerInitializing,
errorDetails: MobileScannerErrorDetails(
message: MobileScannerErrorCode.controllerInitializing.message,
),
);
}
if (!_isDisposed) {
value = value.copyWith(isStarting: true);
}
final options = StartOptions(
cameraDirection: cameraDirection ?? facing,
cameraLensType: cameraLensType ?? lensType,
cameraResolution: cameraResolution,
detectionSpeed: detectionSpeed,
detectionTimeoutMs: detectionTimeoutMs,
formats: formats,
returnImage: returnImage,
torchEnabled: torchEnabled,
invertImage: invertImage,
autoZoom: autoZoom,
initialZoom: initialZoom,
);
try {
_setupListeners();
final viewAttributes = await MobileScannerPlatform.instance.start(
options,
);
if (!_isDisposed) {
value = value.copyWith(
availableCameras: viewAttributes.numberOfCameras,
cameraDirection: viewAttributes.cameraDirection,
cameraLensType: options.cameraLensType,
isInitialized: true,
isStarting: false,
isRunning: true,
size: viewAttributes.size,
deviceOrientation: viewAttributes.initialDeviceOrientation,
// Provide the current torch state.
// Updates are provided by the `torchStateStream`.
torchState: viewAttributes.currentTorchMode,
);
}
} on MobileScannerException catch (error) {
// The initialization finished with an error.
// To avoid stale values, reset the camera direction,
// output size, torch state and zoom scale to the defaults.
if (!_isDisposed) {
value = value.copyWith(
cameraDirection: CameraFacing.unknown,
isInitialized: true,
isStarting: false,
isRunning: false,
error: error,
size: Size.zero,
torchState: TorchState.unavailable,
zoomScale: 1,
);
}
}
}