Skip to main content

srag_printer 0.2.0 copy "srag_printer: ^0.2.0" to clipboard
srag_printer: ^0.2.0 copied to clipboard

PlatformAndroid

Flexible Flutter thermal printing package for PDF widgets, PDFs, and image frames over network, USB, and Bluetooth.

srag_printer

srag_printer

A flexible Flutter thermal printing package for printing PDF widgets, PDF bytes, and image frames through ESC/POS thermal printers.


It is intentionally generic. It does not know about your POS models, tax rules, ZATCA QR generation, preferences, providers, or app assets. Your app builds the content; srag_printer renders and prints it.

Screenshots #

English Receipt    Arabic Receipt    Bilingual Receipt

English Receipt Arabic Receipt (RTL) Bilingual Receipt
LTR layout Full RTL support English + Arabic side by side

Acknowledgements #

srag_printer is built on top of excellent Flutter/Dart packages, including:

  • pdf for building PDF documents with Dart widgets.
  • pdfx for rendering PDF pages into images.
  • image for image decoding and processing.
  • esc_pos_utils_plus for ESC/POS command generation utilities.
  • usb_serial for Android USB serial communication (through the optional srag_printer_usb package).
  • flutter_blue_plus for Bluetooth Low Energy discovery and communication.
  • Android's BluetoothSocket (through this plugin's own Java code) for Classic Bluetooth SPP printing.
  • ffi for Windows RAW driver and serial port bindings.

Many thanks to the maintainers and contributors of these packages.

What This Package Does #

  • Prints any pw.Widget from package:pdf/widgets.dart.
  • Prints existing PDF bytes.
  • Prints existing image frames as List<Uint8List>.
  • Converts PDF pages into thermal-printer-width image frames.
  • Converts images to ESC/POS raster commands.
  • Sends bytes through network, USB, Bluetooth BLE, Windows driver, or Windows serial transports.
  • Provides generic receipt widgets as optional helpers.
  • Provides generic device discovery by type/platform.

Installation #

Add the package to your app:

dependencies:
  srag_printer: ^0.2.0

Then import:

import 'package:srag_printer/srag_printer.dart';
import 'package:pdf/widgets.dart' as pw;

Android USB printing (optional) #

Android USB support lives in the separate srag_printer_usb package, so apps that only print over the network or Bluetooth do not pull in a USB plugin. To print over USB on Android, add it and register it once at startup:

dependencies:
  srag_printer: ^0.2.0
  srag_printer_usb: ^0.1.0
import 'package:srag_printer_usb/srag_printer_usb.dart';

void main() {
  SragPrinterUsb.register();
  runApp(const MyApp());
}

Without it, Android USB discovery returns no devices and creating a USB transport throws PrinterUnsupportedPlatformException. USB on Windows goes through the built-in COM serial and driver transports and needs nothing extra.

Platform Setup and Permissions #

The package sends bytes to printers, but each application owns its platform permissions. The example app includes these settings as a reference.

Android #

Add the permissions you need to android/app/src/main/AndroidManifest.xml. Keep hardware features optional if your app can still use network printing when USB or Bluetooth hardware is unavailable.

<!-- Network printers, usually raw TCP on port 9100. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- USB host mode for Android USB printers. -->
<uses-feature android:name="android.hardware.usb.host" android:required="false" />

<!-- Bluetooth for Android 11 and below. Location is required by Android for BLE scanning. -->
<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.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />

<!-- Bluetooth for Android 12+. -->
<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />

Runtime permissions are still required before Bluetooth discovery. The example uses permission_handler to request bluetoothScan, bluetoothConnect, and locationWhenInUse on Android.

USB note: Android USB access is device-selection dependent. The OS may show a USB permission prompt when a USB transport opens the selected device.

iOS #

For network printers on the local network and BLE discovery/connect, add usage descriptions to ios/Runner/Info.plist:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to discover and connect to BLE thermal printers.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to discover and connect to BLE thermal printers.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>This app connects to network thermal printers on your local network.</string>

iOS does not support generic USB thermal printer access in v1. Classic Bluetooth SPP is also not available for generic printers; use network or BLE printers that expose writable BLE characteristics.

macOS #

If your macOS app uses the app sandbox, add outbound network and Bluetooth entitlements. The example adds these to both debug/profile and release entitlements:

<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>

Windows #

No manifest permissions are required for raw TCP sockets, installed Windows printer RAW output, or COM-port access. Users may still need normal OS-level access to the selected printer/port, and firewall rules can affect network printers.

Linux #

Network printing can work with normal socket access. USB/serial access usually depends on system groups and udev rules such as dialout or lp; configure those at the OS level for your target device.

Platform Support #

Capability Windows Android iOS
Print pw.Widget Yes Yes Yes
Print PDF bytes Yes Yes Yes
Print image frames Yes Yes Yes
Network TCP/IP Yes Yes Yes
USB direct Yes via serial/driver Yes, with srag_printer_usb Not in v1
Windows driver RAW Yes No No
Windows COM serial Yes No No
Bluetooth classic (SPP) Not in v1 Yes, paired devices No (iOS does not allow it)
BLE Bluetooth Yes Possible Possible
Generic USB discovery COM/system devices USB devices, with srag_printer_usb No
Network discovery Manual IP/port Manual IP/port Manual IP/port

Quick Start: Network Printer #

final printer = SragPrinter(
  transport: NetworkPrinterTransport(host: '192.168.1.50', port: 9100),
  config: const SragPrinterConfig(
    paper: SragPaper.mm80(headDots: 528),
  ),
);

await printer.printWidget(
  (_) => pw.Column(
    children: [
      pw.Text('Hello from srag_printer'),
      pw.Text('Printed from a PDF widget'),
    ],
  ),
);

Use this when your app wants total control over layout:

await printer.printWidget(
  (_) => pw.Directionality(
    textDirection: pw.TextDirection.rtl,
    child: pw.Column(
      children: [
        pw.Text('فاتورة تجريبية'),
        pw.Divider(),
        pw.Text('You can render any pdf widget here.'),
      ],
    ),
  ),
);
final pdfBytes = await buildMyPdfSomewhereElse();
await printer.printPdf(pdfBytes);
final frames = <Uint8List>[pngFrame1, pngFrame2];
await printer.printImages(frames);

Receipt Widgets #

The receipt widgets are optional helpers. You can use them, mix them with your own pw.Widgets, or ignore them completely.

await printer.printWidget(
  (_) => SragReceipt(
    textDirection: pw.TextDirection.ltr,
    children: [
      ReceiptHeader(
        titles: ['Simplified Tax Invoice', 'فاتورة ضريبية مبسطة'],
        infoRows: const [
          ReceiptKeyValue(label: 'Invoice No', value: '10001'),
          ReceiptKeyValue(label: 'Date', value: '2026-06-27'),
        ],
      ),
      ReceiptTable<Map<String, String>>(
        columns: [
          ReceiptTableColumn(title: 'Product', flex: 4, valueBuilder: (x) => x['name']!),
          ReceiptTableColumn(title: 'Qty', valueBuilder: (x) => x['qty']!),
          ReceiptTableColumn(title: 'Total', valueBuilder: (x) => x['total']!),
        ],
        rows: const [
          {'name': 'Coffee', 'qty': '1', 'total': '12.00'},
        ],
      ),
      ReceiptTotals(
        rows: const [
          ReceiptKeyValue(label: 'Subtotal', value: '12.00'),
          ReceiptKeyValue(label: 'Tax', value: '1.80'),
          ReceiptKeyValue(label: 'Total', value: '13.80'),
        ],
      ),
      ReceiptFooter(lines: const ['Thank you']),
    ],
  ),
);

Arabic / RTL and Custom Fonts #

srag_printer ships with Almarai (Regular + Bold) as bundled package assets. These fonts support both Latin and Arabic glyphs out of the box.

Loading the default fonts #

Call SragFonts.load() once at app startup (or before the first print). After that, SragReceiptStyle.defaults() automatically uses the bundled fonts:

import 'package:srag_printer/srag_printer.dart';

// Call once, e.g. in initState or main:
await SragFonts.load();

// SragReceiptStyle.defaults() now uses Almarai automatically:
final style = SragReceiptStyle.defaults();

Creating a style with the loaded fonts #

final style = SragReceiptStyle.defaults(
  font: almaraiRegular,
  boldFont: almaraiBold,
);

Arabic receipt (RTL) #

await printer.printWidget(
  (_) => SragReceipt(
    style: style,
    textDirection: pw.TextDirection.rtl,
    children: [
      ReceiptHeader(
        style: style,
        titles: const ['مقهى البيت', 'فاتورة ضريبية'],
        infoRows: const [
          ReceiptKeyValue(label: 'رقم الفاتورة', value: '10002'),
          ReceiptKeyValue(label: 'التاريخ', value: '2026-06-27'),
        ],
      ),
      ReceiptTable<Map<String, String>>(
        style: style,
        columns: [
          ReceiptTableColumn(title: 'المنتج', flex: 2, valueBuilder: (x) => x['name']!),
          ReceiptTableColumn(title: 'الكمية', valueBuilder: (x) => x['qty']!),
          ReceiptTableColumn(title: 'الإجمالي', valueBuilder: (x) => x['total']!),
        ],
        rows: const [
          {'name': 'قهوة لاتيه', 'qty': '2', 'total': '24.00'},
        ],
      ),
      ReceiptTotals(
        style: style,
        rows: const [
          ReceiptKeyValue(label: 'المجموع', value: '24.00'),
          ReceiptKeyValue(label: 'الضريبة', value: '2.40'),
          ReceiptKeyValue(label: 'الإجمالي', value: '26.40'),
        ],
      ),
      ReceiptFooter(style: style, lines: const ['شكراً لزيارتكم!']),
    ],
  ),
);

Bilingual receipt (English + Arabic) #

Use trailingLabel on ReceiptKeyValue to display both languages side by side:

await printer.printWidget(
  (_) => SragReceipt(
    style: style,
    children: [
      ReceiptHeader(
        style: style,
        titles: const ['Coffee House | مقهى البيت'],
        infoRows: const [
          ReceiptKeyValue(label: 'Invoice', value: '10003', trailingLabel: 'فاتورة'),
          ReceiptKeyValue(label: 'Date', value: '2026-06-27', trailingLabel: 'التاريخ'),
        ],
      ),
      // ... table, totals, footer with style: style
    ],
  ),
);

Using your own fonts #

You are not limited to the bundled Almarai font. Load any .ttf file and pass it to SragReceiptStyle.defaults() to override the defaults:

import 'package:flutter/services.dart' show rootBundle;
import 'package:pdf/widgets.dart' as pw;

final myFont = pw.Font.ttf(await rootBundle.load('assets/fonts/MyFont-Regular.ttf'));
final myBold = pw.Font.ttf(await rootBundle.load('assets/fonts/MyFont-Bold.ttf'));

final style = SragReceiptStyle.defaults(font: myFont, boldFont: myBold);

Custom Table Rows #

ReceiptTable<MyItem>(
  columns: columns,
  rows: items,
  rowBuilder: (context, item, columns) {
    return pw.Column(
      children: [
        pw.Text(item.name),
        pw.Text('Custom options, modifiers, or notes'),
      ],
    );
  },
);

QR Codes #

srag_printer does not generate QR content. Generate the QR in your app, then pass it as an image or widget:

ReceiptQrSection.image(qrPngBytes);
ReceiptQrSection.widget(myQrPdfWidget);

Discovery #

Discovery is generic and platform-aware. It does not hardcode printer brands or choose for you:

final devices = await SragPrinterDiscovery.discover(
  request: const PrinterDiscoveryRequest(
    connectionType: PrinterConnectionType.usb,
  ),
);

final selected = devices.first; // Your UI or app policy chooses this.
final transport = selected.createTransport();

Optional filters are app-controlled:

final devices = await SragPrinterDiscovery.discover(
  request: const PrinterDiscoveryRequest(
    connectionType: PrinterConnectionType.usb,
    filters: {'nameContains': 'printer'},
  ),
);

Classic Bluetooth (Android) #

On Android, Bluetooth discovery lists every paired device, Classic and BLE, with its type in device.metadata['bluetoothType'] (a BluetoothDeviceType: classic, le, dual, or unknown). createTransport() then picks the transport:

  • Paired classic, dual, and unknown devices print over Classic Bluetooth SPP through ClassicBluetoothPrinterTransport. This covers the built-in printers of POS terminals, which appear as a paired virtual device (often InnerPrinter at 00:11:22:33:44:55) that reports no type.
  • le devices, and devices found by the BLE scan, print over BLE through BluetoothPrinterTransport.

Pair Classic printers in the Android Bluetooth settings first; discovery does not scan for unpaired Classic devices. Android 12+ needs the BLUETOOTH_CONNECT runtime permission to list paired devices and connect.

Paper and Print Options #

const config = SragPrinterConfig(
  paper: SragPaper.mm58(headDots: 384),
  chunkSize: 512,
  chunkDelay: Duration(milliseconds: 6),
  feedLines: 3,
  cutAfterPrint: true,
);

Use SragPaper.custom(widthMm: ..., headDots: ...) for uncommon printers.

Troubleshooting #

  • Cannot reach printer at host:port: check IP, port, network, and firewall.
  • No writable BLE characteristic found: the printer may use a proprietary BLE service. Classic SPP printers are printed over SPP automatically on Android once they are paired.
  • Failed to open Classic Bluetooth printer: make sure the printer is on, paired in Android Bluetooth settings, and not connected to another phone.
  • USB transport is supported on Android: use Windows driver/serial transports on Windows.
  • Image frame could not be decoded: pass PNG/JPEG bytes, not raw pixels.
  • Cut command ignored: some printers do not have a cutter, or the driver may block raw ESC/POS commands.

Migration Guide #

Keep app-specific logic in your app:

SalesInvoice / app model -> your adapter -> pw.Widget or receipt data -> srag_printer

Do not move tax, QR generation, ZATCA logic, local preferences, or app assets into this package.

Migrating from 0.1.x to 0.2.0 #

  • UsbPrinterTransport moved to srag_printer_usb. If you print over USB on Android, add that package, call SragPrinterUsb.register() at startup, and import UsbPrinterTransport from package:srag_printer_usb/srag_printer_usb.dart.
  • Nothing changes for network, Bluetooth, or Windows printing.
  • Bluetooth discovery now skips paired devices outside Android instead of throwing on iOS, and waits for the adapter to leave the unknown state before scanning.

FAQ #

Can I print any Flutter widget?
No. The input must be a pdf/widgets.dart widget (pw.Widget), not a normal Flutter Widget.

Can the package discover network printers automatically?
Not in v1. Use manual IP/port for reliability and predictable behavior.

Does iOS support USB printing?
Generic USB thermal printing is not supported in v1.

Does the package generate QR codes?
No. Pass a ready QR image or pw.Widget.

6
likes
150
points
408
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flexible Flutter thermal printing package for PDF widgets, PDFs, and image frames over network, USB, and Bluetooth.

Repository (GitHub)
View/report issues

Topics

#printer #thermal-printer #esc-pos #receipt #bluetooth

License

MIT (license)

Dependencies

esc_pos_utils_plus, ffi, flutter, flutter_blue_plus, image, pdf, pdfx

More

Packages that depend on srag_printer

Packages that implement srag_printer