PDA Scanner Plus

Configurable Android PDA barcode scanner broadcasts for Flutter. Select a vendor profile for known defaults or provide your own broadcast action and barcode data key.

Android only. This package receives Android intent broadcasts emitted by the scanner or wedge application installed on the PDA.

Installation

dependencies:
  pda_scanner_plus: ^1.0.0

Device setup

In the PDA's scanner, wedge, or DataWedge application, select Intent output or Broadcast output. Configure its intent action and barcode-data extra key to the values for the selected profile below. The device setup is required; this package cannot configure proprietary scanner applications itself.

Note: PDA scanner settings are configurable. Built-in profiles provide vendor defaults, but they will not work if the device's configured broadcast action or data key has been changed. Use profile overrides or PdaScanner.custom to match the current device settings.

Configure the scanner

Create one PdaScanner for the PDA configuration used by your app, then call initialize() once during app startup. Most applications use one scanner instance.

For a supported device, use its prebuilt profile:

final scanner = PdaScanner.profile(PdaScannerProfiles.urovo);
await scanner.initialize();

For a device with custom Intent Output settings, use a custom configuration:

final scanner = PdaScanner.custom(
  broadcastAction: 'com.vendor.scanner.RESULT',
  dataKey: 'barcode',
);
await scanner.initialize();

Use either a profile or a custom configuration for each scanner instance. A profile already supplies the broadcast action and data key; provide overrides only when that specific device uses different values.

Consume scan data

scanner.scans is a Stream<ScanResult>. Each scan's decoded barcode is the non-null String in ScanResult.data.

final StreamSubscription<ScanResult> subscription = scanner.scans.listen((scan) {
  final String barcode = scan.data;
  print(barcode);
});

Subscribe to scanner.scans after initialization. Each ScanResult contains:

  • data — the decoded barcode as a non-null String.
  • profileId — the selected profile ID, when a profile was used.
  • additionalData — an immutable map of optional extras requested through additionalExtraKeys.
// Fields on your State class.
final scanner = PdaScanner.profile(PdaScannerProfiles.urovo);
String barcode = '';
late final StreamSubscription<ScanResult> subscription;

@override
void initState() {
  super.initState();
  subscription = scanner.scans.listen((scan) {
    setState(() => barcode = scan.data);
    debugPrint('Symbology: ${scan.additionalData['symbology']}');
  });
}

@override
void dispose() {
  subscription.cancel();
  super.dispose();
}

Lifecycle

Keep the configured PdaScanner instance for the lifetime of barcode scanning. Subscribe to scanner.scans where scan data is needed and cancel each subscription when its owner is disposed.

Call await scanner.dispose() when that scanner is no longer needed. It unregisters the Android receiver only when that instance is still active. The plugin supports one active scanner configuration per Flutter engine, which matches the normal one-PDA, one-scanner-app setup.

Every profile value can be overridden for device-specific firmware:

final scanner = PdaScanner.profile(
  PdaScannerProfiles.newland,
  dataKey: 'SCAN_BARCODE2',
);
await scanner.initialize();

For Zebra or any unknown device, provide both settings configured in the device scanner application:

final scanner = PdaScanner.custom(
  broadcastAction: 'com.zebra.scanner.ACTION',
  dataKey: 'com.symbol.datawedge.data_string',
);
await scanner.initialize();

Profiles

Profile Broadcast action Data key
AIDA com.android.scanner.broadcast scandata
SEUIC com.android.server.scannerservice.broadcast scannerdata
UROVO android.intent.ACTION_DECODE_DATA barcode_string
NEWLAND nlscan.action.SCANNER_RESULT SCAN_BARCODE1
Datalogic com.datalogic.decodewedge.decode_action com.datalogic.decode.intentwedge.barcode_string
Honeywell com.honeywell.sample.action.BARCODE Override required
iData android.intent.action.SCANRESULT Override required
Zebra, PL, KAICOM, HIKVISION Override required Override required

Honeywell and iData include their documented action but require a model-specific dataKey. Zebra, PL, KAICOM, and HIKVISION require both values until their device-specific settings are confirmed. All values are always overrideable.

Errors and security

initialize throws PdaScannerConfigurationException for incomplete or blank configuration, and may throw PlatformException if Android rejects setup. Malformed native events are surfaced as PdaScannerEventException on scans.

try {
  final scanner = PdaScanner.profile(PdaScannerProfiles.honeywell);
  await scanner.initialize();
} on PdaScannerConfigurationException catch (error) {
  // Supply the Honeywell model's dataKey before retrying.
  debugPrint(error.message);
} on PlatformException catch (error) {
  debugPrint('Native scanner setup failed: ${error.message}');
}

The Android receiver must be exported to receive broadcasts from vendor scanner apps. Any app can therefore send the configured action. Treat scans as untrusted input: validate their format and never use a barcode alone as authentication or authorization proof.

Additional extras

Pass additionalExtraKeys to expose vendor extras in ScanResult.additionalData:

final scanner = PdaScanner.profile(
  PdaScannerProfiles.urovo,
  additionalExtraKeys: {'symbology': 'barcode_type'},
);
await scanner.initialize();

Contributing profiles

Profiles are maintained in lib/src/pda_scanner_profiles.dart. Contributions must include public vendor documentation or reproducible device evidence for each action/data-key pair, an accompanying test, and a README table update. If either required value is unknown, add a partial profile with a clear note; it must require callers to supply the missing override rather than guessing.

Libraries

pda_scanner_plus
Configurable PDA barcode scanning for Android.