flutter_zebra_scale

A Flutter plugin for integrating Zebra Scanner SDK (v2.6.25.0) to connect, control, and interact with Zebra barcode scanners and scales on Android.

Features

  • Scanner Connection Management

    • Connect/disconnect to scanners by ID
    • Get list of available scanners
    • Get list of active (connected) scanners
    • Enable/disable scanner detection
    • Enable/disable Bluetooth scanner discovery
  • Scale Operations

    • Enable/disable scale
    • Read weight (single reading)
    • Live weight reading (continuous updates)
    • Zero scale
    • Reset scale
  • Barcode Scanning

    • Real-time barcode scanning events
    • Barcode data and type information
    • Scanner ID tracking
  • Event Streaming

    • Scanner appeared/disappeared events
    • Connection/disconnection events
    • Barcode scan events
    • Firmware update events
    • Configuration update events
    • Image/video/binary data events

Requirements

  • Flutter SDK: >=3.3.0
  • Dart SDK: ^3.9.2
  • Android: minSdk 24 (Android 7.0+)
  • Zebra Scanner SDK: v2.6.25.0 (included as AAR)

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_zebra_scale:
    path: ../flutter_zebra_scale  # or use git/pub.dev URL

Android Setup

The plugin uses compileOnly for the Zebra Scanner SDK AAR to avoid Android Gradle Plugin 8+ restrictions. You MUST add repository configuration and the AAR dependency explicitly in your app's android/app/build.gradle file.

  1. Add repository configuration before your dependencies block:
// Automatically find the latest flutter_zebra_scale plugin version
def pubCache = new File("${System.getProperty('user.home')}/.pub-cache/hosted/pub.dev")
def flutterZebraScaleLibsPath = null
def latestVersion = null

if (pubCache.exists()) {
    pubCache.eachDir { pluginDir ->
        if (pluginDir.name.startsWith('flutter_zebra_scale-')) {
            def libsDir = new File(pluginDir, "android/libs")
            if (libsDir.exists() && libsDir.isDirectory()) {
                def versionStr = pluginDir.name.replace('flutter_zebra_scale-', '')
                if (latestVersion == null) {
                    latestVersion = versionStr
                    flutterZebraScaleLibsPath = libsDir.absolutePath
                }
            }
        }
    }
}

if (flutterZebraScaleLibsPath == null) {
    throw new GradleException("flutter_zebra_scale plugin libs not found in pub cache.")
}

repositories {
    flatDir {
        dirs flutterZebraScaleLibsPath
        // ... your other flatDir entries
    }
}
  1. Add the AAR dependency in your dependencies block:
dependencies {
    // Zebra Scanner SDK - required for the plugin
    implementation(name: 'barcode_scanner_library_v2.6.25.0-release', ext: 'aar')

    // ... your other dependencies
}
  1. Add required permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH"
    android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
  1. For Android 12+ (API 31+), you may need to request runtime permissions for Bluetooth.

Usage

Initialize the SDK

import 'package:flutter_zebra_scale/flutter_zebra_scale.dart';

final flutterZebraScale = FlutterZebraScale();

// Initialize the SDK (optional - auto-initializes on plugin attach)
await flutterZebraScale.initialize();

Connect to a Scanner

// Connect to scanner with ID 123
bool success = await flutterZebraScale.connect(123);
if (success) {
  print('Connected successfully');
}

Get Available Scanners

final result = await flutterZebraScale.getAvailableScanners();
final scanners = result['scanners'] as List;
print('Found ${result['count']} scanners');

for (var scanner in scanners) {
  print('Scanner ID: ${scanner['scannerID']}');
  print('Name: ${scanner['scannerName']}');
  print('Type: ${scanner['connectionTypeName']}');
  print('Active: ${scanner['isActive']}');
}

Listen to Events

FlutterZebraScale().eventStream.listen((event) {
  final eventType = event['eventType'];
  final data = event['data'] as Map<String, dynamic>;
  
  switch (eventType) {
    case 'barcode':
      print('Barcode scanned: ${data['barcodeData']}');
      print('Type: ${data['barcodeType']}');
      print('Scanner ID: ${data['scannerID']}');
      break;
      
    case 'sessionEstablished':
      print('Connected to: ${data['scannerName']}');
      break;
      
    case 'sessionTerminated':
      print('Disconnected from scanner: ${data['scannerID']}');
      break;
      
    case 'scannerAppeared':
      print('Scanner appeared: ${data['scannerName']}');
      break;
  }
});

Scale Operations

// Enable scale
await flutterZebraScale.enableScale(scannerId);

// Read weight once
final weightData = await flutterZebraScale.readWeight(scannerId);
print('Weight: ${weightData?['weight']} ${weightData?['weightMode']}');
print('Status: ${weightData?['statusText']}');

// Start live weight reading (updates every second)
await flutterZebraScale.startLiveWeight(scannerId);

// Zero the scale
await flutterZebraScale.zeroScale(scannerId);

// Reset the scale
await flutterZebraScale.resetScale(scannerId);

// Disable scale
await flutterZebraScale.disableScale(scannerId);

Disconnect from Scanner

await flutterZebraScale.disconnect(scannerId);

API Reference

Methods

Connection Management

  • Future<bool> initialize() - Initialize the SDK
  • Future<bool> connect(int scannerId) - Connect to a scanner
  • Future<bool> disconnect(int scannerId) - Disconnect from a scanner
  • Future<Map<String, dynamic>> getAvailableScanners() - Get list of available scanners
  • Future<Map<String, dynamic>> getActiveScanners() - Get list of active scanners
  • Future<bool> enableScannersDetection(bool enable) - Enable/disable scanner detection
  • Future<bool> enableBluetoothScannerDiscovery(bool enable) - Enable/disable Bluetooth discovery
  • Future<Map<String, dynamic>> updateScannersList() - Refresh scanner list

Scale Operations

  • Future<bool> enableScale(int scannerId) - Enable scale
  • Future<bool> disableScale(int scannerId) - Disable scale
  • Future<Map<String, dynamic>?> readWeight(int scannerId) - Read weight once
  • Future<bool> zeroScale(int scannerId) - Zero the scale
  • Future<bool> resetScale(int scannerId) - Reset the scale
  • Future<bool> startLiveWeight(int scannerId) - Start continuous weight reading
  • Future<bool> stopLiveWeight() - Stop continuous weight reading

Event Streaming

  • Stream<Map<String, dynamic>> get eventStream - Cached stream of SDK events (preferred; same pattern as flutter_elavon)
  • Stream<Map<String, dynamic>> getEventStream() - Same as eventStream

Event Types

  • scannerAppeared - Scanner becomes available
  • scannerDisappeared - Scanner becomes unavailable
  • sessionEstablished - Connection established
  • sessionTerminated - Connection terminated
  • barcode - Barcode scanned
  • firmwareUpdate - Firmware update event
  • auxScannerAppeared - Auxiliary scanner appeared
  • configurationUpdate - Configuration updated
  • image - Image received
  • video - Video frame received
  • binaryData - Binary data received

Scanner Information

Each scanner map contains:

  • scannerID (int) - Unique scanner identifier
  • scannerName (String) - Scanner name
  • scannerModel (String) - Scanner model
  • scannerSerialNumber (String) - Hardware serial number
  • connectionType (int) - Connection type code
  • connectionTypeName (String) - Human-readable connection type
  • isActive (bool) - Whether scanner is connected
  • isAutoReconnectionEnabled (bool) - Auto-reconnection status

Weight Data

Weight reading returns:

  • weight (String) - Weight value
  • weightMode (String) - Unit (kg, lb, etc.)
  • status (int) - Status code (0-6)
  • statusText (String) - Human-readable status

Barcode Data

Barcode event contains:

  • barcodeData (String) - Scanned barcode string
  • barcodeType (int) - Barcode type code
  • scannerID (int) - Scanner that scanned the barcode

Example

See the example/ directory for a complete example app demonstrating all features.

Supported Connection Types

  • Bluetooth Classic (BT_NORMAL)
  • Bluetooth Low Energy (BT_LE)
  • USB SNAPI
  • USB CDC

Troubleshooting

AAR Dependency Not Found

If you encounter errors like:

Could not find barcode_scanner_library_v2.6.25.0-release

Make sure you've added the code to find the plugin's libs directory and added the AAR dependency in your android/app/build.gradle file as shown in the Android Setup section.

Duplicate Class Errors

If you encounter duplicate class errors like:

Duplicate class com.zebra.barcode.sdk.BarcodeScanner found in modules...

This usually means the AAR is being included multiple times. Make sure you only add it once in your app's build.gradle dependencies section.

Notes

  • The plugin automatically initializes the SDK when attached
  • Scanner detection and Bluetooth discovery are enabled by default after initialization
  • All operational modes (BT_NORMAL, SNAPI, BT_LE, USB_CDC) are enabled for maximum compatibility
  • Events are streamed asynchronously via EventChannel
  • Scale operations require the scanner to support scale functionality

License

See LICENSE file for details.

Credits

This plugin integrates the Zebra Scanner SDK v2.6.25.0 for Android.