starxpand_sdk_wrapper

A Flutter plugin that provides a simple interface to Star Micronics receipt printers using the official StarXpand SDK for Android and iOS.

Features

  • 🔍 Device Discovery - Automatically discover Star printers on your network or connected via USB/Bluetooth
  • 🖨️ Image Printing - Print images directly from Flutter
  • 💰 Cash Drawer Control - Open cash drawers connected to Star printers
  • 📊 Status Monitoring - Get real-time printer status (paper level, cover state, errors)
  • 🔌 Multiple Interfaces - Support for USB & bluetooth connections

Supported Printers

This plugin supports Star Micronics printers compatible with the StarXpand SDK, I've personally tested the TSP100III but all other StarXpand-compatible models should work.

Platform Requirements

  • iOS: 13.0 or higher
  • Android: API 26 (Android 8.0) or higher
  • Star Micronics printer with StarXpand SDK support

Installation

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

dependencies:
  starxpand_sdk_wrapper: ^1.0.0

Then run: flutter pub get

iOS Setup

Add these keys to your ios/Runner/Info.plist:

<!--> For Bluetooth -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to connect to Star printers</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth to connect to Star printers</string>

<!--> For USB -->
<key>UISupportedExternalAccessoryProtocols</key>
<array>
    <string>jp.star-m.starpro</string>
</array>

Android Setup

Add these permissions to your android/app/src/main/AndroidManifest.xml:

<!-- For Bluetooth -->
<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" />

<!-- For USB -->
<uses-feature android:name="android.hardware.usb.host" />

<!-- For Network -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Usage

Import the package

import 'package:starxpand_sdk_wrapper/starxpand_sdk_wrapper.dart';

Discover Printers

// Start discovery for all interface types
await StarXpandSdkWrapper.startDiscovery(
  interfaces: [InterfaceType.bluetooth, InterfaceType.usb],
  timeoutMs: 8000,
);

// Listen for discovered devices
StarXpandSdkWrapper.onDeviceFound.listen((device) {
  print('Found printer: ${device.identifier}');
  print('Model: ${device.model}');
  print('Interface: ${device.iface}');
});

// Listen for discovery completion
StarXpandSdkWrapper.onDiscoveryDone.listen((_) {
  print('Discovery finished');
});

// Stop discovery manually if needed
await StarXpandSdkWrapper.stopDiscovery();

Connect to a Printer

// Listen for connection status
StarXpandSdkWrapper.onConnectionComplete.listen((success) {
  print('Connection ${success ? "successful" : "failed"}');
});

A simple way to design your receipt is to use the PDF package (https://pub.dev/packages/pdf) then simply convert that to a Uint8List.

// Load your image as bytes
Uint8List imageBytes = await loadImageBytes();

// Print the image (width in dots, typically 576 for 3-inch printers)
bool success = await StarXpandSdkWrapper.printImage(
  imageBytes: imageBytes,
  width: 576,
);

if (success) {
  print('Image sent to printer');
}

Open Cash Drawer

bool success = await StarXpandSdkWrapper.openCashDrawer();

if (success) {
  print('Cash drawer opened');
}

Get Printer Status

Status status = await StarXpandSdkWrapper.getStatus();

print('Online: ${status.online}');
print('Cover Open: ${status.coverOpen}');
print('Paper Empty: ${status.paperEmpty}');

// Monitor status changes in real-time (if monitor: true was set during connect)
StarXpandSdkWrapper.onStatus.listen((status) {
  if (status.paperEmpty) {
    print('Warning: Printer is out of paper!');
  }
});

Disconnect

await StarXpandSdkWrapper.disconnect();

Complete Example

import 'package:flutter/material.dart';
import 'package:starxpand_sdk_wrapper/starxpand_sdk_wrapper.dart';

class PrinterExample extends StatefulWidget {
  @override
  _PrinterExampleState createState() => _PrinterExampleState();
}

class _PrinterExampleState extends State<PrinterExample> {
  List<Device> _devices = [];
  Device? _selectedDevice;

  @override
  void initState() {
    super.initState();
    _startDiscovery();
  }

  Future<void> _startDiscovery() async {
    StarXpandSdkWrapper.onDeviceFound.listen((device) {
      setState(() {
        _devices.add(device);
      });
    });

    await StarXpandSdkWrapper.startDiscovery();
  }

  Future<void> _connectToPrinter(Device device) async {
    bool connected = await StarXpandSdkWrapper.connect(
      identifier: device.identifier,
      iface: device.iface,
      monitor: true,
    );

    if (connected) {
      setState(() {
        _selectedDevice = device;
      });
    }
  }

  Future<void> _printTestImage() async {
    // Load your image bytes here
    Uint8List imageBytes = ...;

    await StarXpandSdkWrapper.printImage(
      imageBytes: imageBytes,
      width: 576,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Star Printer Example')),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _devices.length,
              itemBuilder: (context, index) {
                final device = _devices[index];
                return ListTile(
                  title: Text(device.model ?? 'Unknown'),
                  subtitle: Text(device.identifier ?? ''),
                  trailing: Icon(
                    _selectedDevice == device
                        ? Icons.check_circle
                        : Icons.circle_outlined,
                  ),
                  onTap: () => _connectToPrinter(device),
                );
              },
            ),
          ),
          if (_selectedDevice != null)
            ElevatedButton(
              onPressed: _printTestImage,
              child: Text('Print Test Image'),
            ),
        ],
      ),
    );
  }
}

API Reference

Methods

Method Description Returns
startDiscovery({interfaces, timeoutMs}) Start discovering printers Future<void>
stopDiscovery() Stop discovery Future<void>
connect({identifier, iface, monitor}) Connect to a printer Future<bool>
disconnect() Disconnect from printer Future<void>
printImage({imageBytes, width}) Print an image Future<bool>
openCashDrawer() Open cash drawer Future<bool>
getStatus() Get printer status Future<Status>

Streams

Stream Type Description
onDeviceFound Stream<Device> Emits when a printer is discovered
onDiscoveryDone Stream<void> Emits when discovery completes
onConnectionComplete Stream<bool> Emits connection result
onStatus Stream<Status> Emits printer status updates

Types

InterfaceType

enum InterfaceType { bluetooth, usb }

Device

class Device {
  String? identifier;  // Connection identifier
  InterfaceType? iface; // Interface type
  String? model;        // Printer model
}

Status

class Status {
  bool? online;      // Printer is online and ready
  bool? coverOpen;   // Printer cover is open
  bool? paperEmpty;  // Printer is out of paper
  String? raw;       // Raw status data
}

Troubleshooting

iOS

Problem: Printer not discovered via Bluetooth

Ensure Bluetooth permissions are added to Info.plist Check that Bluetooth is enabled on the device Make sure the printer is in pairing mode

Problem: USB printer not working

Add the external accessory protocol to Info.plist Ensure the printer is properly connected

Android

Problem: Bluetooth discovery not working on Android 12+

Request BLUETOOTH_SCAN and BLUETOOTH_CONNECT permissions at runtime Target SDK 31+ requires these permissions

Problem: Network printer not discovered

Ensure the device and printer are on the same network Check firewall settings

Acknowledgments

Star Micronics for the StarXpand Android SDK & iOS SDK