Zebra_Datawedge_With_Flutter
Flutter plugin that works with Zebra DataWedge on compatible Zebra Android devices.
This README is written for beginners and junior Flutter developers. It explains what each major part of the package does and how to use it in a real app.
Table of Contents
- What This Package Does
- Core Concepts You Must Know
- Platform and Device Requirements
- Installation
- First Working Integration (Step-by-Step)
- Understanding Events and Payloads
- Profile Setup in Depth
- API Guide by Use Case
- Reliable Command Handling Pattern
- Advanced Examples
- Troubleshooting Guide
- License
- Legal and Trademark Notice
- Pub.dev Publishing Checklist
- References
What This Package Does
Zebra devices use a system service called DataWedge for scanning and data capture. Instead of writing Android broadcast intent code manually, this package gives you:
- A clean Flutter API through
ZebraDataWedge. - Strongly typed constants and request models.
- Generic command methods for future DataWedge APIs.
- A unified event stream for:
- Scan data
- Command results
- Notifications
- Debug messages
In simple terms:
- You send commands from Flutter to DataWedge.
- DataWedge executes them.
- Your app receives scan events and status events.
Core Concepts You Must Know
Before coding, learn these 4 terms:
-
Profile A DataWedge profile is a configuration set (scanner settings, output mode, app binding).
-
App association The profile must be associated with your app package, or your app will not receive scans.
-
Intent output DataWedge sends scan data as Android intents. This plugin listens and forwards them to Flutter.
-
Command result Most commands can return success/failure info. You should listen to command result events for reliability.
Platform and Device Requirements
- Android only
- Zebra devices with DataWedge installed
- Flutter SDK >= 3.3.0
- Dart SDK compatible with package constraints
Important:
- Feature availability depends on DataWedge version and hardware model.
- Some APIs (workflow, RFID, scale, scanner switching) are device-specific.
Installation
Install from Pub.dev (recommended)
Add this to your app pubspec.yaml:
dependencies:
zebra_datawedge: ^0.1.4
Then run:
flutter pub get
Local path install (for plugin development)
dependencies:
zebra_datawedge:
path: ../zebra_datawedge
First Working Integration (Step-by-Step)
This is the simplest production-style setup.
Step 1: Import and create one shared service
import 'dart:async';
import 'package:zebra_datawedge/zebra_datawedge.dart';
class ZebraScannerService {
ZebraScannerService({required this.androidPackageName});
final String androidPackageName;
final ZebraDataWedge _dataWedge = ZebraDataWedge();
StreamSubscription<DataWedgeEvent>? _subscription;
String? lastBarcode;
String? lastLabelType;
String? lastCommandResult;
Future<void> initialize() async {
final bool available = await _dataWedge.isAvailable();
if (!available) {
throw StateError(
'DataWedge is not available on this device. Use a Zebra device with DataWedge installed.',
);
}
await _dataWedge.configureClassicBarcodeProfile(
profileName: 'MY_APP_PROFILE',
packageName: androidPackageName,
);
await _dataWedge.switchToProfile('MY_APP_PROFILE');
await _dataWedge.registerForDefaultNotifications();
_subscription = _dataWedge.events.listen(_onEvent);
}
void _onEvent(DataWedgeEvent event) {
if (event.isScan) {
lastBarcode = event.scanData;
lastLabelType = event.labelType;
return;
}
if (event.isCommandResult) {
final String command = event.command ?? 'UNKNOWN_COMMAND';
final String result = event.result ?? 'UNKNOWN_RESULT';
lastCommandResult = '$command -> $result';
return;
}
if (event.isNotification) {
final String notificationType = event.notificationType ?? 'UNKNOWN_NOTIFICATION';
final String status = event.scannerStatus ?? 'UNKNOWN_STATUS';
lastCommandResult = 'Notification: $notificationType -> $status';
}
}
Future<void> dispose() async {
await _subscription?.cancel();
}
}
Why this code is structured this way:
androidPackageNamemust match your Android app package (applicationId). It is used to bind the DataWedge profile to your app.ZebraDataWedge _dataWedgeis one shared API instance for all scanner operations.initialize()starts withisAvailable()so you fail fast on unsupported devices.configureClassicBarcodeProfile(...)creates a practical default profile for most barcode apps.switchToProfile(...)ensures the active profile is the one your app expects.registerForDefaultNotifications()helps you observe scanner/profile state._dataWedge.events.listen(_onEvent)is the main event bridge from Android to Flutter.dispose()cancels the stream subscription to prevent memory leaks.
Step 2: Use it from your UI
late final ZebraScannerService scannerService;
@override
void initState() {
super.initState();
scannerService = ZebraScannerService(
androidPackageName: 'com.example.my_app',
);
scannerService.initialize();
}
@override
void dispose() {
scannerService.dispose();
super.dispose();
}
How to set the package name correctly:
- Open
android/app/build.gradlein your app. - Find
defaultConfigand readapplicationId. - Use that exact value in
androidPackageNameand profile app association.
Step 3: Test the flow
- Open the app on a Zebra device.
- Trigger scanner (hardware button or soft scan API).
- Confirm scan events arrive.
- Confirm command results show success.
Understanding Events and Payloads
This package exposes 2 streams:
scanStream: rawMap<String, dynamic>events: typedDataWedgeEvent
Most apps should use events.
Event types
-
scanTypical keys:data: scanned textlabelType: barcode typeextras: full intent extras map
-
commandResultTypical keys:commandresult(usuallySUCCESSorFAILURE)commandIdresultInforesultInfoText
-
notificationTypical keys:notificationTypestatusprofileNameraw
-
debugTypical keys:message
Recommended event handling strategy
- Handle
scanin your business logic. - Log
commandResultfor diagnostics and reliability. - Use
notificationto react to scanner/profile state changes.
Profile Setup in Depth
This package gives you 2 profile approaches.
A) Fast setup with configureClassicBarcodeProfile
Use this when you want a reliable default profile quickly. It configures:
- BARCODE plugin enabled
- INTENT output enabled (broadcast)
- KEYSTROKE output disabled
- App association set to your package
await ZebraDataWedge().configureClassicBarcodeProfile(
profileName: 'MY_APP_PROFILE',
packageName: 'com.example.my_app',
);
Parameter explanation:
profileName: the DataWedge profile to create or update.packageName: your Android app id that receives scan intents.- Optional arguments (not shown) let you customize intent action, delivery mode, activities, and notification behavior.
B) Advanced setup with DataWedgeProfileBuilder
Use this for large apps with multiple scanner modes.
final DataWedgeProfileConfiguration profile = DataWedgeProfileBuilder(
profileName: 'WAREHOUSE_PROFILE',
configMode: DataWedgeConfigMode.createIfNotExist,
)
.setProfileEnabled(true)
.addPlugin(
DataWedgePluginConfiguration(
pluginName: DataWedgePluginName.barcode,
resetConfig: true,
paramList: <String, dynamic>{
'scanner_selection': 'auto',
'scanner_selection_by_identifier': DataWedgeScannerIdentifier.auto,
'scanner_input_enabled': 'true',
},
),
)
.addPlugin(
DataWedgePluginConfiguration(
pluginName: DataWedgePluginName.intent,
resetConfig: true,
paramList: <String, dynamic>{
'intent_output_enabled': 'true',
'intent_action': 'com.example.my_app.SCAN',
'intent_category': DataWedgeApi.defaultIntentCategory,
'intent_delivery': DataWedgeIntentDelivery.broadcast,
},
),
)
.addAppAssociation(
const DataWedgeAppAssociation(
packageName: 'com.example.my_app',
activityList: <String>[DataWedgeApi.wildcard],
),
)
.build();
await ZebraDataWedge().setConfig(profile);
Builder chain explanation:
DataWedgeProfileBuilder(...)creates a mutable builder object..setProfileEnabled(true)ensures profile is active.- First
.addPlugin(...)enables BARCODE input settings. - Second
.addPlugin(...)enables INTENT output settings. .addAppAssociation(...)binds profile to app package and activities..build()converts builder state into immutableDataWedgeProfileConfiguration.setConfig(profile)sends final config bundle to DataWedge.
API Guide by Use Case
1) Availability and setup
isAvailableconfigureProfileconfigureClassicBarcodeProfileswitchToProfile
2) Profile management
createProfilecloneProfilerenameProfiledeleteProfilesdeleteAllDeletableProfilessetConfigapplyProfileConfigurationgetConfigsetDefaultProfileresetDefaultProfile
3) Notifications
registerForNotificationunregisterForNotificationregisterForDefaultNotifications
Notification constants:
DataWedgeNotificationType.scannerStatusDataWedgeNotificationType.profileSwitchDataWedgeNotificationType.configurationUpdateDataWedgeNotificationType.workflowStatus
4) Queries and diagnostics
getActiveProfilegetProfilesListgetVersionInfogetDataWedgeStatusgetScannerStatusenumerateScannersenumerateTriggersenumerateWorkflowsgetDisabledAppListgetIgnoreDisabledProfiles
5) Runtime scanner control
startSoftScanstopSoftScantoggleSoftScansoftScanTriggerenableScannerdisableScannersuspendScannerresumeScannersoftRfidTriggersoftVoiceTriggerswitchScannerByIndexswitchScannerByIdentifierswitchScannerParamsswitchDataCapturesetDataWedgeEnabled
6) Import/export and app control
importConfigexportConfigsetDisabledAppListsetIgnoreDisabledProfiles
7) Scale and Bluetooth notification APIs
getWeightsetScaleToZeronotifyBluetoothScannercustomNotifyBluetoothScanner
8) Generic future-proof APIs
sendCommandsendCommandBundlesendIntent
Use these when Zebra introduces a new command that is not yet wrapped by a typed helper.
Reliable Command Handling Pattern
When sending commands, always think in request/response style:
- Send command with a unique
commandTag. - Keep
requestResult: true. - Listen for
commandResultevents. - Match by
commandIdor command name. - Handle failures with retry or fallback.
Example:
await ZebraDataWedge().sendCommand(
command: DataWedgeApi.getVersionInfo,
value: '',
commandTag: 'GET_VERSION_FOR_STARTUP_CHECK',
requestResult: true,
);
What each argument means:
command: which DataWedge API command you are sending.value: command payload; query commands usually use an empty string.commandTag: your custom tracking id prefix for logs and correlation.requestResult: when true, DataWedge returns acommandResultevent.
Advanced Examples
Soft scan for a specific scanner
await ZebraDataWedge().softScanTrigger(
action: DataWedgeSoftScanAction.toggle,
scannerSelectionByIdentifier: DataWedgeScannerIdentifier.bluetoothRs6000,
);
Switch scanner parameters at runtime
await ZebraDataWedge().switchScannerParams(
scannerSelectionByIdentifier: DataWedgeScannerIdentifier.internalImager,
parameters: <String, dynamic>{
'illumination_mode': 'off',
},
);
Switch data capture to workflow mode
await ZebraDataWedge().switchDataCapture(
targetPlugin: DataWedgeSwitchDataCaptureTarget.workflow,
paramList: <String, dynamic>{
'workflow_name': DataWedgeWorkflowName.idScanning,
'workflow_input_source': DataWedgeWorkflowInputSource.camera,
},
);
Import and export DataWedge config
await ZebraDataWedge().exportConfig(
const DataWedgeExportConfigRequest(
folderPath: '/storage/emulated/0/Download/',
exportType: DataWedgeExportType.profileConfig,
profileName: 'MY_APP_PROFILE',
),
);
await ZebraDataWedge().importConfig(
const DataWedgeImportConfigRequest(
folderPath: '/sdcard/configFolder',
fileList: <String>['dwprofile_MY_APP_PROFILE.db'],
),
);
Troubleshooting Guide
Problem: No scan data arrives
Checklist:
- Confirm device is Zebra and DataWedge is installed.
- Confirm
isAvailable()returns true. - Confirm profile is associated with your app package.
- Confirm INTENT output is enabled.
- Confirm your app is using the same package name used in profile config.
Problem: Commands seem ignored
Checklist:
- Keep
requestResult: trueand inspectcommandResultevents. - Check DataWedge status using
getDataWedgeStatus. - Ensure profile exists before switching to it.
- Validate command parameters against Zebra docs.
Problem: Works on one device, fails on another
Checklist:
- Compare DataWedge versions using
getVersionInfo. - Compare available scanners with
enumerateScanners. - Compare supported workflows using
enumerateWorkflows.
License
This package is distributed under the MIT License. See LICENSE for full terms.
Legal and Trademark Notice
- This is an independent open-source project and is not affiliated with or endorsed by Zebra Technologies.
- This package works with Zebra devices and DataWedge APIs; it is not an official Zebra plugin.
- Zebra, DataWedge, and related marks are trademarks of Zebra Technologies Corporation and/or its affiliates.
- This plugin is designed to use public DataWedge APIs exposed on compatible Zebra Android devices.
- You are responsible for following Zebra device software terms, API documentation terms, and any trademark usage rules in your product, docs, or store listing.
References
- DataWedge Overview: https://techdocs.zebra.com/datawedge/latest/guide/about/
- DataWedge API Reference: https://techdocs.zebra.com/datawedge/latest/guide/api/
- DataWedge Profiles: https://techdocs.zebra.com/datawedge/latest/guide/profiles/
- Feature Matrix: https://techdocs.zebra.com/datawedge/latest/guide/matrix/