start method

Future<MobileScannerArguments?> start({
  1. CameraFacing? cameraFacingOverride,
})

Start scanning for barcodes. Upon calling this method, the necessary camera permission will be requested.

Returns an instance of MobileScannerArguments when the scanner was successfully started. Returns null if the scanner is currently starting.

Throws a MobileScannerException if starting the scanner failed.

Implementation

Future<MobileScannerArguments?> start({
  CameraFacing? cameraFacingOverride,
}) async {
  if (isStarting) {
    debugPrint("Called start() while starting.");
    return null;
  }

  events ??= _eventChannel
      .receiveBroadcastStream()
      .listen((data) => _handleEvent(data as Map));

  isStarting = true;

  // Check authorization status
  if (!kIsWeb) {
    final MobileScannerState state = MobileScannerState
        .values[await _methodChannel.invokeMethod('state') as int? ?? 0];
    switch (state) {
      case MobileScannerState.undetermined:
        bool result = false;

        try {
          result =
              await _methodChannel.invokeMethod('request') as bool? ?? false;
        } catch (error) {
          isStarting = false;
          throw const MobileScannerException(
            errorCode: MobileScannerErrorCode.genericError,
          );
        }

        if (!result) {
          isStarting = false;
          throw const MobileScannerException(
            errorCode: MobileScannerErrorCode.permissionDenied,
          );
        }

        break;
      case MobileScannerState.denied:
        isStarting = false;
        throw const MobileScannerException(
          errorCode: MobileScannerErrorCode.permissionDenied,
        );
      case MobileScannerState.authorized:
        break;
    }
  }

  // Start the camera with arguments
  Map<String, dynamic>? startResult = {};
  try {
    startResult = await _methodChannel.invokeMapMethod<String, dynamic>(
      'start',
      _argumentsToMap(cameraFacingOverride: cameraFacingOverride),
    );
  } on PlatformException catch (error) {
    MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError;

    final String? errorMessage = error.message;

    if (kIsWeb) {
      if (errorMessage == null) {
        errorCode = MobileScannerErrorCode.genericError;
      } else if (errorMessage.contains('NotFoundError') ||
          errorMessage.contains('NotSupportedError')) {
        errorCode = MobileScannerErrorCode.unsupported;
      } else if (errorMessage.contains('NotAllowedError')) {
        errorCode = MobileScannerErrorCode.permissionDenied;
      } else {
        errorCode = MobileScannerErrorCode.genericError;
      }
    }

    isStarting = false;

    throw MobileScannerException(
      errorCode: errorCode,
      errorDetails: MobileScannerErrorDetails(
        code: error.code,
        details: error.details as Object?,
        message: error.message,
      ),
    );
  }

  if (startResult == null) {
    isStarting = false;
    throw const MobileScannerException(
      errorCode: MobileScannerErrorCode.genericError,
    );
  }

  final hasTorch = startResult['torchable'] as bool? ?? false;
  hasTorchState.value = hasTorch;
  if (hasTorch && torchEnabled) {
    torchState.value = TorchState.on;
  }

  isStarting = false;
  return startArguments.value = MobileScannerArguments(
    size: kIsWeb
        ? Size(
            startResult['videoWidth'] as double? ?? 0,
            startResult['videoHeight'] as double? ?? 0,
          )
        : toSize(startResult['size'] as Map? ?? {}),
    hasTorch: hasTorch,
    textureId: kIsWeb ? null : startResult['textureId'] as int?,
    webId: kIsWeb ? startResult['ViewID'] as String? : null,
  );
}