zebra_rfid_plus 0.0.2
zebra_rfid_plus: ^0.0.2 copied to clipboard
A Flutter plugin for Zebra RFID readers (RFD8500, RFD40, RFD90) using the Zebra RFID API3 SDK. Supports Bluetooth and USB transport, inventory scanning, tag access, pre-filters, and singulation control.
zebra_rfid_plus #
A Flutter plugin for Zebra RFID readers using the official Zebra RFID API3 SDK v2.0.5.238.
Supports inventory scanning, Impinj GEN2X extensions (Tag Focus, Tag Quiet, Tag Protect, Fast Tag),
tag read/write/lock/kill, pre-filters, singulation control, USB Data Wedge mode, and a stateful
ZebraRfidController for easy integration.
Android only. The Zebra RFID SDK does not support iOS.
Table of Contents #
- Supported Devices
- Features
- Installation
- Quick Start
- Low-Level API
- API Reference
- Models
- Impinj GEN2X Extensions
- Error Handling
- Device Compatibility Notes
- SDK Reference
- Disclaimer
Supported Devices #
| Device | Transport | Min Android | GEN2X |
|---|---|---|---|
| RFD8500 | Bluetooth | 8 | ✗ |
| RFD40 | Bluetooth | 10 | ✗ |
| RFD40 Premium | Bluetooth | 10 | ✗ |
| RFD40 Premium Plus | Bluetooth | 10 | ✅ |
| RFD90 | Bluetooth / USB | 10 | ✅ |
| FXR90 | USB / ZIOTC | 10 | ✅ |
| FXP20 | USB | 10 | ✗ |
| TC53e | Integrated | 11 | ✅ |
| EM45 | Integrated | 10 | ✗ |
| ET6X | Integrated | 10 | ✗ |
| TC22R | Integrated | 14 | ✅ |
| WS50 | USB Data Wedge | 10 | ✗ |
| MC33xR | Integrated | 11 | ✅ |
Features #
- 🔌 Connect via Bluetooth, USB, Serial, or USB Data Wedge (WS50)
- 📡 Real-time tag read stream with EPC and RSSI
- 🔘 Physical trigger button events (press / release)
- 🔦 Barcode scan support (when in barcode trigger mode)
- ⚙️ Antenna power, RF mode, singulation (S0–S3)
- 🔍 Pre-filter by EPC pattern, TID, or User memory
- 📝 Tag memory read / write / lock / kill
- 🧬 Impinj GEN2X extensions (SDK v2.0.5.214+):
- Tag Focus — inventory only unseen tags
- Tag Quiet — suppress already-processed tags
- Tag Visibility — hide from non-Impinj readers
- Tag Protection — prevent unauthorised kill/lock
- Fast Tag — dense population throughput (v2.0.5.238+)
- 🧠
ZebraRfidController— ChangeNotifier with de-duplication + auto trigger linking - 📊
getReaderCapabilities— firmware version, max power index, GEN2X support flag - 🔔 Typed
ZebraRfidExceptionwithZebraRfidErrorCodeconstants
Installation #
1. Add dependency #
dependencies:
zebra_rfid_plus: ^0.0.1
2. Place Zebra SDK AARs #
The Zebra RFID SDK is proprietary and must be obtained separately from Zebra. Download: https://www.zebra.com/ap/en/support-downloads/software/rfid-software/rfid-sdk-for-android.html
Copy all .aar files from the Zebra SDK zip into android/app/libs/:
android/app/libs/
rfidhostlib.aar
rfidseriallib.aar
BarcodeScannerLibrary.aar
API3_CMN-release-2.0.5.238.aar
API3_TRANSPORT-release-2.0.5.238.aar
API3_NGE-protocolrelease-2.0.5.238.aar
API3_NGE-Transportrelease-2.0.5.238.aar
API3_NGEUSB-Transportrelease-2.0.5.238.aar
API3_LLRP-release-2.0.5.238.aar
API3_ASCII-release-2.0.5.238.aar
API3_INTERFACE-release-2.0.5.238.aar
API3_READER-release-2.0.5.238.aar
API3_ZIOTC-release-2.0.5.238.aar
API3_ZIOTCTRANSPORT-release-2.0.5.238.aar
In android/app/build.gradle:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'])
}
3. Permissions #
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Quick Start — ZebraRfidController (recommended) #
ZebraRfidController is a ChangeNotifier that manages connection state, tag de-duplication,
trigger linking, and error state — ready to use directly with ListenableBuilder or setState.
import 'package:zebra_rfid_plus/zebra_rfid_plus.dart';
class _ScannerPageState extends State<ScannerPage> {
final _controller = ZebraRfidController();
@override
void initState() {
super.initState();
_controller.init();
_controller.addListener(() => setState(() {}));
// Physical trigger press auto-starts/stops inventory
_controller.linkTriggerToInventory(enabled: true);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Status: ${_controller.connectionStatus.name}'),
Text('Tags found: ${_controller.tagCount}'),
if (_controller.lastError != null)
Text('Error: ${_controller.lastError}',
style: const TextStyle(color: Colors.red)),
ElevatedButton(
onPressed: () => _controller.isConnected
? _controller.disconnect()
: _controller.connect(),
child: Text(_controller.isConnected ? 'Disconnect' : 'Connect'),
),
ElevatedButton(
onPressed: _controller.isConnected
? (_controller.isScanning
? _controller.stopInventory
: _controller.startInventory)
: null,
child: Text(_controller.isScanning ? 'Stop' : 'Start Inventory'),
),
ElevatedButton(
onPressed: _controller.clearTags,
child: const Text('Clear Tags'),
),
Expanded(
child: ListView.builder(
itemCount: _controller.tags.length,
itemBuilder: (_, i) {
final tag = _controller.tags[i];
return ListTile(
title: Text(tag.tagId),
subtitle: Text('RSSI: ${tag.peakRssi} dBm'),
);
},
),
),
],
);
}
}
Low-Level API — ZebraRfid static methods #
import 'package:zebra_rfid_plus/zebra_rfid_plus.dart';
// Initialise once
await ZebraRfid.initialize();
// Discover readers
final readers = await ZebraRfid.getAvailableReaders();
// Connect (uses first available reader if name is omitted)
await ZebraRfid.connect(readerName: readers.first.name);
// Configure antenna
await ZebraRfid.setAntennaConfig(
const RfidAntennaConfig(transmitPowerIndex: 270),
);
// Listen to tag reads
ZebraRfid.onTagRead.listen((tag) {
print('${tag.tagId} RSSI=${tag.peakRssi}');
});
// Scan
await ZebraRfid.startInventory();
await Future.delayed(const Duration(seconds: 5));
await ZebraRfid.stopInventory();
// Read a memory bank
await ZebraRfid.readTagMemory(
tagId: 'E28011C1A5000062F792696D',
memoryBank: RfidMemoryBank.tid,
wordCount: 6,
);
// Result arrives on onTagRead with tag.memoryBankData set
await ZebraRfid.disconnect();
await ZebraRfid.dispose();
API Reference #
Connection #
| Method | Returns | Description |
|---|---|---|
ZebraRfid.initialize() |
Future<void> |
Init SDK. Call once. |
ZebraRfid.dispose() |
Future<void> |
Release all resources. |
ZebraRfid.getAvailableReaders({transport}) |
Future<List<RfidReaderDevice>> |
Discover readers. |
ZebraRfid.connect({readerName, transport}) |
Future<bool> |
Connect to reader. |
ZebraRfid.disconnect() |
Future<void> |
Disconnect. |
ZebraRfid.isConnected() |
Future<bool> |
Connection check. |
ZebraRfid.getReaderCapabilities() |
Future<RfidReaderCapabilities> |
Firmware, power, GEN2X flag. |
Inventory #
| Method | Description |
|---|---|
ZebraRfid.startInventory() |
Begin scanning. Tags arrive on onTagRead. |
ZebraRfid.stopInventory() |
Stop scanning. |
Configuration #
| Method | Description |
|---|---|
ZebraRfid.setAntennaConfig(config) |
Power index, RF mode, tari. |
ZebraRfid.setSingulationConfig(config) |
Session S0–S3, inventory state A/B. |
ZebraRfid.setTriggerMode({rfidMode}) |
RFID or barcode trigger. |
ZebraRfid.resetToDefaults() |
Restore SDK defaults. |
Pre-filters #
| Method | Description |
|---|---|
ZebraRfid.addPreFilter(filter) |
Filter by EPC/TID/User pattern. |
ZebraRfid.clearPreFilters() |
Remove all filters. |
ZebraRfid.getPreFilterCount() |
Count active filters. |
Tag Access #
| Method | Description |
|---|---|
ZebraRfid.readTagMemory({tagId, memoryBank, ...}) |
Read memory bank. Result on onTagRead. |
ZebraRfid.writeTagMemory({tagId, memoryBank, data, ...}) |
Write to memory bank. |
ZebraRfid.lockTag({tagId, params}) |
Lock a memory field. |
ZebraRfid.killTag({tagId, killPassword}) |
⚠️ Permanently kill a tag. |
Impinj GEN2X Extensions #
Requires RFD40 Premium Plus, RFD90, FXR90, MC33xR, TC53e, or TC22R. Always check
RfidReaderCapabilities.supportsGen2xbefore calling these.
| Method | Description |
|---|---|
ZebraRfid.setTagFocus(config) |
New-tags-only inventory. |
ZebraRfid.setTagQuiet(config) |
Suppress already-processed tags. |
ZebraRfid.setTagVisibility(config) |
Hide tags from non-Impinj readers. |
ZebraRfid.setTagProtection(config) |
Prevent unauthorised kill/lock. |
ZebraRfid.setFastTag(config) |
Dense population throughput mode (v2.0.5.238+). |
Streams #
| Stream | Type | Description |
|---|---|---|
ZebraRfid.onTagRead |
Stream<RfidTag> |
Tag reads + memory bank access results. |
ZebraRfid.onConnectionStatus |
Stream<RfidConnectionEvent> |
Connection state changes. |
ZebraRfid.onTriggerEvent |
Stream<bool> |
true = pressed, false = released. |
ZebraRfid.onBarcodeRead |
Stream<String> |
Barcode data (barcode mode only). |
Models #
/// Tag read event — also used for memory bank access results.
class RfidTag {
final String tagId; // EPC identifier (hex string)
final int peakRssi; // Peak signal strength in dBm
final DateTime timestamp;
final int? seenCount;
final int? firstSeenTime;
final int? lastSeenTime;
final String? memoryBankData; // Populated after readTagMemory()
}
/// Discovered reader.
class RfidReaderDevice {
final String name;
final RfidTransport transport; // bluetooth | usb | serial | usbDataWedge
final RfidDeviceType deviceType; // Auto-detected from reader hostname
bool get supportsGen2x;
}
/// Reader hardware capabilities.
class RfidReaderCapabilities {
final String modelName;
final String? serialNumber;
final String? firmwareVersion;
final int antennaCount;
final int maxTransmitPowerIndex;
final bool supportsGen2x;
final bool hasTrigger;
}
/// Connection event delivered on onConnectionStatus.
class RfidConnectionEvent {
final RfidConnectionStatus status; // connected | disconnected | connecting | error
final String? readerName;
final String? message;
}
Enums #
enum RfidTransport { bluetooth, usb, serial, usbDataWedge }
enum RfidMemoryBank { epc, tid, user, reserved }
enum RfidSession { s0, s1, s2, s3 }
enum RfidInventoryState { stateA, stateB }
enum RfidConnectionStatus{ connected, disconnected, connecting, error }
enum RfidLockField { epcMemory, userMemory, tid, accessPassword, killPassword }
enum RfidLockPrivilege { lock, unlock, permanentLock, permanentUnlock, securedLock }
Impinj GEN2X Extensions #
final caps = await ZebraRfid.getReaderCapabilities();
if (caps.supportsGen2x) {
// Only inventory tags not seen before in this session
await ZebraRfid.setTagFocus(
const ImpinjTagFocusConfig(enable: true, antennaId: 1),
);
// Suppress tags already processed
await ZebraRfid.setTagQuiet(
const ImpinjTagQuietConfig(
masks: [TagQuietMask.tid],
target: ImpinjTarget.sl,
action: ImpinjStateAwareAction.assertSl,
),
);
// High-throughput mode for dense tag populations (v2.0.5.238+)
await ZebraRfid.setFastTag(
const ImpinjFastTagConfig(enable: true),
);
}
Error Handling #
All methods throw ZebraRfidException on failure.
try {
await ZebraRfid.startInventory();
} on ZebraRfidException catch (e) {
switch (e.code) {
case ZebraRfidErrorCode.notConnected:
print('Reader is not connected');
case ZebraRfidErrorCode.gen2xNotSupported:
print('This reader does not support GEN2X');
default:
print('RFID error ${e.code}: ${e.message}');
if (e.detail != null) print('Detail: ${e.detail}');
}
}
Error Codes #
| Constant | Value | When thrown |
|---|---|---|
notConnected |
NOT_CONNECTED |
Operation called without a connected reader |
connectFailed |
CONNECT_FAILED |
Connection attempt failed |
noReader |
NO_READER |
No reader discovered |
inventoryFailed |
INVENTORY_FAILED |
startInventory / stopInventory failed |
configFailed |
CONFIG_FAILED |
Antenna or singulation config failed |
filterFailed |
FILTER_FAILED |
Pre-filter operation failed |
readFailed |
READ_FAILED |
readTagMemory failed |
writeFailed |
WRITE_FAILED |
writeTagMemory failed |
lockFailed |
LOCK_FAILED |
lockTag failed |
killFailed |
KILL_FAILED |
killTag failed |
notInitialized |
NOT_INITIALIZED |
Plugin channel not set up (missing SDK AARs) |
tagFocusFailed |
TAG_FOCUS_FAILED |
setTagFocus failed |
tagQuietFailed |
TAG_QUIET_FAILED |
setTagQuiet failed |
tagVisibilityFailed |
TAG_VISIBILITY_FAILED |
setTagVisibility failed |
tagProtectionFailed |
TAG_PROTECTION_FAILED |
setTagProtection failed |
fastTagFailed |
FAST_TAG_FAILED |
setFastTag failed |
gen2xNotSupported |
GEN2X_NOT_SUPPORTED |
GEN2X called on non-capable reader |
Device Compatibility Notes #
- RFD8500: Bluetooth only. Android 8–14. Validated on TC56, TC52, MC33xR, TC26, TC53, TC73, EC50, TC52AX, TC22R.
- WS50: USB Data Wedge mode added in SDK v2.0.5.238. Use
RfidTransport.usbDataWedge. - FXR90: Supports ZIOTC transport in addition to standard API3.
- GEN2X features: Require EU-RED GEN2X compliant firmware (SDK v2.0.5.226+).
- Fast Tag: Requires SDK v2.0.5.238+ and compatible reader firmware.
SDK Reference #
- Official docs: https://techdocs.zebra.com/dcs/rfid/android/2-0-2-124/guide/introduction-to-api3-sdk/
- Download SDK: https://www.zebra.com/ap/en/support-downloads/software/rfid-software/rfid-sdk-for-android.html
Contributing #
See CONTRIBUTING.md for guidelines.
License #
MIT — see LICENSE.
Disclaimer #
Unofficial community wrapper. Not affiliated with Zebra Technologies Corporation. The Zebra RFID API3 SDK is proprietary software — obtain it separately and comply with Zebra's licence terms.