thermal_printer_billbay 1.0.9
thermal_printer_billbay: ^1.0.9 copied to clipboard
A comprehensive Flutter plugin for ESC/POS thermal printers via Bluetooth Classic (SPP). Supports Arabic shaping, multiple code pages, receipt templates, images, QR codes, barcodes, and all standard E [...]
thermal_printer_billbay #
A comprehensive Flutter plugin for ESC/POS thermal printers via Bluetooth Classic (SPP).
Supports Android (Bluetooth Classic) and iOS (MFi via ExternalAccessory).
Features #
- Bluetooth Classic (SPP) connection — scan, pair, connect, send
- Full ESC/POS command set — text, bold, underline, reverse, font sizes, alignment
- Arabic text shaping — automatic joining forms, Lam-Alef ligatures, bidi reversal
- Multiple code pages — Win-1256, CP864, CP720, UTF-8, or any custom number
- Paper sizes — 58mm, 72mm, 80mm, 110mm, and custom
- Multi-column rows — grid-based column layout for receipts
- Receipt templates — ready-made invoice builder with items, tax, QR, footer
- Images — print PNG/JPEG/BMP with auto monochrome conversion
- QR codes — native ESC/POS QR commands
- Barcodes — UPC-A, UPC-E, EAN-13, EAN-8, Code 39, ITF, Codabar, Code 93, Code 128
- Horizontal lines — solid, dashed, dotted, double, star, equals
- Paper cut, cash drawer, beep
- Raw bytes pass-through for custom commands
Table of Contents #
- Installation
- Android Setup
- iOS Setup
- Quick Start
- Finding Your Printer's Code Page
- Printing Text
- Text Styles
- Arabic Text
- Multi-Column Rows
- Horizontal Lines
- QR Codes
- Barcodes
- Images
- Receipt Templates
- Paper Cut, Cash Drawer & Beep
- Full API Reference
- Distribution Guide
1. Installation #
Option A: Local Path (for development / private use) #
Put the thermal_printer_billbay folder next to your app folder:
my_projects/
thermal_printer_billbay/ ← this plugin
my_app/ ← your Flutter app
In your app's pubspec.yaml:
dependencies:
thermal_printer_billbay:
path: ../thermal_printer_billbay
Option B: Git Repository (for sharing with team) #
Push thermal_printer_billbay to a Git repo (GitHub, GitLab, Bitbucket), then:
dependencies:
thermal_printer_billbay:
git:
url: https://github.com/YOUR_USERNAME/thermal_printer_billbay.git
ref: main # or a specific tag like v1.0.0
Option C: Publish to pub.dev (for public distribution) #
See Section 17: Distribution Guide.
After adding the dependency #
Run in your app folder:
flutter pub get
No additional permission packages needed — the plugin handles Bluetooth permissions internally.
2. Android Setup #
2.1 Permissions #
Add these to your app's android/app/src/main/AndroidManifest.xml (inside the <manifest> tag, before <application>):
<!-- Bluetooth Classic permissions -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<!-- Android 12+ Bluetooth permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Location (required for Bluetooth scanning on Android) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
2.2 Request Permissions at Runtime #
The plugin handles runtime permission requests automatically. Just call:
final printer = ThermalPrinterManager();
// Option A: One-call setup (handles permissions + Bluetooth enable)
final ready = await printer.ensureReady();
if (!ready) return; // permissions denied or Bluetooth off
// Option B: Step by step
final granted = await printer.requestPermissions();
if (!granted) return;
if (!await printer.isBluetoothEnabled()) {
await printer.enableBluetooth();
}
2.3 Min SDK #
Make sure your android/app/build.gradle has minSdk at least 21:
android {
defaultConfig {
minSdk = 21
}
}
3. iOS Setup #
3.1 Info.plist #
Add these to ios/Runner/Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to connect to thermal printers</string>
<key>UISupportedExternalAccessoryProtocols</key>
<array>
<string>com.yourprinter.protocol</string>
</array>
Replace com.yourprinter.protocol with your printer's MFi protocol string (check your printer's documentation).
3.2 Set Protocol in Code #
final printer = ThermalPrinterManager();
await printer.setProtocol('com.yourprinter.protocol');
3.3 Important #
iOS only supports MFi-certified printers via the ExternalAccessory framework. Regular Bluetooth printers that are not MFi certified will not work on iOS.
4. Quick Start #
Here is the simplest possible example — setup, connect, print "Hello World", cut paper:
import 'package:thermal_printer_billbay/thermal_printer_billbay.dart';
// 1. Create the printer manager
final printer = ThermalPrinterManager();
// 2. Ensure permissions + Bluetooth are ready
final ready = await printer.ensureReady();
if (!ready) return;
// 3. Get already-paired devices
final devices = await printer.getBondedDevices();
print('Found ${devices.length} paired devices');
// 4. Connect to the first printer (with auto-retry)
final connected = await printer.connectWithRetry(devices.first.address);
if (!connected) {
print('Failed to connect');
return;
}
// 4. Build ESC/POS commands
final cmd = EscPosCommands(PaperSize.mm80);
cmd.initialize();
cmd.textLn('Hello World!', useLatin: true);
cmd.feed(3);
cmd.cut();
// 5. Send to printer
await printer.sendBytes(cmd.getBytes());
// 6. Disconnect when done
await printer.disconnect();
printer.dispose();
Scanning for New Devices #
final printer = ThermalPrinterManager();
// Listen for discovered devices
printer.scanResults.listen((device) {
print('Found: ${device.name} (${device.address})');
});
// Listen for connection changes
printer.connectionState.listen((connected) {
print('Connected: $connected');
});
// Start scanning (also discovers nearby unpaired devices)
await printer.startScan();
// Stop after 10 seconds
Future.delayed(Duration(seconds: 10), () {
printer.stopScan();
});
5. Finding Your Printer's Code Page #
This is the most important step for Arabic/special characters.
Every thermal printer has a list of code pages, but the numbers are different for every brand. The same encoding (e.g., Windows-1256 Arabic) might be number 46 on one printer and number 60 on another.
How to Find Your Code Page Number #
-
Print a self-test page: Turn off your printer, then hold the FEED button and turn it on. It will print a page showing all supported code pages with their numbers.
-
Look for Arabic code pages: Find entries like:
46: WPC1256or46: Win-1256(Windows-1256 Arabic)22: PC864(IBM Arabic)41: PC864(same encoding, different number!)60: PC1001(another Arabic page)
-
Use the number from YOUR printer's self-test:
// If your printer shows "46: Win-1256" cmd.setCodePage(CodePage.win1256); // sends ESC t 46 // If your printer shows Arabic at number 41 cmd.setCodePageRaw(41); // sends ESC t 41 // For UTF-8 mode (Chinese-brand printers often support this) cmd.setCodePage(CodePage.utf8); // sends FS .
Built-in Code Page Presets #
| Preset | Code Page | Number | Best For |
|---|---|---|---|
CodePage.utf8 |
PC10001 (UTF-8) | FS . | Chinese-brand printers, full Unicode |
CodePage.win1256 |
Win-1256 | 46 | Arabic (Epson standard) |
CodePage.cp864 |
CP864 | 22 | Arabic (IBM standard) |
CodePage.cp720 |
CP720 | 32 | Arabic DOS |
CodePage.pc437 |
PC437 | 0 | USA/Western Europe |
CodePage.win1252 |
WPC1252 | 16 | Western European |
CodePage.pc850 |
PC850 | 2 | Multilingual Latin |
Custom Code Page #
If your printer uses a different number:
// Your printer has Arabic at position 60
cmd.setCodePageRaw(60);
// Or create a reusable CodePage object
final myCodePage = CodePage.customArabic(60);
cmd.setCodePage(myCodePage);
// Parse from user input (number or name)
cmd.setCodePageFromString('60'); // sends ESC t 60
cmd.setCodePageFromString('PC10001'); // sends FS . (UTF-8)
6. Printing Text #
Basic Text #
final cmd = EscPosCommands(PaperSize.mm80);
cmd.initialize();
cmd.setCodePage(CodePage.win1256);
// Print a line (adds line feed at end)
cmd.textLn('Hello World!', useLatin: true);
// Print text without line feed
cmd.text('Same line... ', useLatin: true);
cmd.textLn('continues here', useLatin: true);
// Print a blank line
cmd.newLine();
// Print Arabic text
cmd.textLn('مرحبا بالعالم');
cmd.feed(3);
await printer.sendBytes(cmd.getBytes());
The useLatin Parameter #
useLatin: true— Use for English, numbers, symbols. Sends raw ASCII bytes (fast, always works).useLatin: false(default) — Use for Arabic or mixed text. Applies Arabic shaping and encodes using the selected code page.
7. Text Styles #
Using textStyled() (recommended) #
textStyled() applies styles, prints the text, then automatically resets styles back to normal:
cmd.initialize();
// Bold centered title
cmd.textStyled('MY STORE',
PosStyles(align: PrintAlign.center, bold: true, width: 2, height: 2),
useLatin: true);
// Underlined text
cmd.textStyled('Underlined', PosStyles(underline: true), useLatin: true);
// Double underline
cmd.textStyled('Double underline', PosStyles(doubleUnderline: true), useLatin: true);
// Reverse (white text on black background)
cmd.textStyled('Reversed!', PosStyles(reverse: true), useLatin: true);
// Font B (smaller font, more characters per line)
cmd.textStyled('Small font', PosStyles(fontType: FontType.fontB), useLatin: true);
// Wide text (2x width)
cmd.textStyled('Wide', PosStyles(width: 2), useLatin: true);
// Tall text (2x height)
cmd.textStyled('Tall', PosStyles(height: 2), useLatin: true);
// Combine multiple styles
cmd.textStyled('BIG BOLD',
PosStyles(bold: true, width: 2, height: 2, align: PrintAlign.center),
useLatin: true);
Using Manual Style Commands #
For more control, set styles individually:
cmd.setBold(true);
cmd.setFontSize(2, 2); // width=2, height=2
cmd.setAlign(PrintAlign.center);
cmd.textLn('Custom styled', useLatin: true);
// Reset everything back to normal
cmd.resetStyles();
All Available Styles #
| Style | PosStyles Property | Values |
|---|---|---|
| Alignment | align |
PrintAlign.left, .center, .right |
| Bold | bold |
true / false |
| Underline | underline |
true / false |
| Double underline | doubleUnderline |
true / false |
| Reverse | reverse |
true / false |
| Font | fontType |
FontType.fontA, .fontB |
| Width | width |
1 to 8 (multiplier) |
| Height | height |
1 to 8 (multiplier) |
| Upside down | upsideDown |
true / false |
8. Arabic Text #
Basic Arabic Printing #
cmd.initialize();
cmd.setCodePage(CodePage.win1256); // Use the code page that works for YOUR printer
cmd.textLn('مرحبا بالعالم'); // Hello World
cmd.textLn('اختبار الطباعة العربية'); // Arabic printing test
How Arabic Works #
- Code page tells the printer which character encoding to use
- Arabic shaping converts letters to their correct joined forms (initial, medial, final, isolated)
- Bidi reversal flips the text so it prints right-to-left
The plugin handles steps 2 and 3 automatically when you use textLn() without useLatin: true.
Arabic with UTF-8 Mode #
If your printer supports UTF-8 (FS . command), Arabic shaping uses Unicode Presentation Forms (U+FE70-U+FEFF) which gives the best results:
cmd.setCodePage(CodePage.utf8);
cmd.textLn('مرحبا بالعالم'); // Shaped + UTF-8 encoded
Arabic with Win-1256 #
If your printer uses Windows-1256 (common for Epson-compatible printers), the plugin encodes Arabic using a Win-1256 lookup table:
cmd.setCodePage(CodePage.win1256);
cmd.textLn('مرحبا بالعالم'); // Encoded as Win-1256 bytes
Mixed Arabic and English #
cmd.textLn('الفاتورة Invoice'); // Mixed text
cmd.textLn('Hello مرحبا World');
9. Multi-Column Rows #
Use row() to print tabular data. Column widths are proportional (like a 12-column grid):
// Header row
cmd.row([
PosColumn(text: 'Item', width: 6),
PosColumn(text: 'Qty', width: 2, align: PrintAlign.center),
PosColumn(text: 'Price', width: 4, align: PrintAlign.right),
], useLatin: true);
// Data rows
cmd.row([
PosColumn(text: 'Coffee', width: 6),
PosColumn(text: '2', width: 2, align: PrintAlign.center),
PosColumn(text: '5.00', width: 4, align: PrintAlign.right),
], useLatin: true);
Left-Right Alignment #
For simple label-value pairs:
cmd.leftRight('Subtotal:', '45.00', useLatin: true);
cmd.leftRight('Tax (15%):', '6.75', useLatin: true);
cmd.leftRight('TOTAL:', '51.75', useLatin: true);
10. Horizontal Lines #
cmd.hr(); // ------------------------------------------------
cmd.hr(style: LineStyle.solid); // ------------------------------------------------
cmd.hr(style: LineStyle.dashed); // - - - - - - - - - - - - - - - - - - - - - - - -
cmd.hr(style: LineStyle.dotted); // ................................................
cmd.hr(style: LineStyle.doubleLine); // ================================================
cmd.hr(style: LineStyle.star); // ************************************************
cmd.hr(style: LineStyle.equals); // ================================================
// Custom character
cmd.hr(customChar: '~'); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The line width is automatically calculated based on your paper size (48 chars for 80mm, 32 for 58mm, etc.).
11. QR Codes #
cmd.printQrCode(
'https://example.com',
size: 6, // Module size: 1-16 (default: 6)
errorLevel: QrErrorLevel.medium, // L, M, Q, H (default: M)
align: PrintAlign.center, // Alignment (default: center)
);
QR Error Correction Levels #
| Level | Recovery | Best For |
|---|---|---|
QrErrorLevel.low |
~7% | Short URLs, clean environment |
QrErrorLevel.medium |
~15% | General use (default) |
QrErrorLevel.quartile |
~25% | Receipts that may get crumpled |
QrErrorLevel.high |
~30% | Harsh environments |
12. Barcodes #
cmd.printBarcode(
'1234567890128',
BarcodeType.ean13,
height: 80, // Barcode height in dots (default: 80)
width: 2, // Bar width: 2-6 (default: 2)
textPosition: 2, // 0=none, 1=above, 2=below, 3=both
align: PrintAlign.center,
);
Supported Barcode Types #
| Type | Data Format |
|---|---|
BarcodeType.upcA |
11-12 digits |
BarcodeType.upcE |
6-8 digits |
BarcodeType.ean13 |
12-13 digits |
BarcodeType.ean8 |
7-8 digits |
BarcodeType.code39 |
A-Z, 0-9, space, $%+-./ |
BarcodeType.itf |
Even number of digits |
BarcodeType.codabar |
0-9, A-D, $+-./: |
BarcodeType.code93 |
ASCII 0-127 |
BarcodeType.code128 |
ASCII 0-127 (most flexible) |
13. Images #
Print any image (PNG, JPEG, BMP). It's automatically converted to monochrome and scaled to fit the paper width:
import 'dart:io';
// Load image from file
final imageBytes = await File('path/to/logo.png').readAsBytes();
cmd.printImage(
imageBytes,
maxWidth: 384, // Max width in dots (optional, defaults to paper width)
threshold: 127, // Black/white threshold: 0-255 (default: 127)
align: PrintAlign.center,
);
From Flutter Assets #
import 'package:flutter/services.dart';
final data = await rootBundle.load('assets/logo.png');
final imageBytes = data.buffer.asUint8List();
cmd.printImage(imageBytes);
14. Receipt Templates #
Full Receipt #
final cmd = EscPosCommands(PaperSize.mm80);
cmd.setCodePage(CodePage.win1256);
final receipt = ReceiptTemplate(
cmd: cmd,
storeName: 'MY STORE',
storeAddress: '123 Main Street',
storePhone: '555-1234',
storeEmail: '[email protected]',
currency: '\$', // Currency symbol before prices
);
receipt.build(
items: [
ReceiptItem(name: 'Coffee', quantity: 2, price: 5.00),
ReceiptItem(name: 'Sandwich', quantity: 1, price: 8.50),
ReceiptItem(name: 'Cookie', quantity: 3, price: 2.00, discount: 1.00),
],
taxRate: 0.15, // 15% tax
discount: 2.0, // Overall discount amount
receiptNumber: '001234',
cashierName: 'Ahmad',
customerName: 'John',
footerText: 'Thank you for your purchase!',
footerTextArabic: 'شكرا لزيارتكم',
qrData: 'https://mystore.com/receipt/001234',
barcodeData: '001234',
cutAfter: true, // Auto cut paper after receipt
);
await printer.sendBytes(cmd.getBytes());
This prints:
MY STORE
123 Main Street
Tel: 555-1234
[email protected]
------------------------------------------------
Receipt #: 001234
Date: 2026-02-07 14:30
Cashier: Ahmad
Customer: John
------------------------------------------------
Item Qty Price Total
- - - - - - - - - - - - - - -
Coffee 2 5.00 10.00
Sandwich 1 8.50 8.50
Cookie 3 2.00 5.00
Disc: -1.00
- - - - - - - - - - - - - - -
Subtotal: 23.50
Discount: -2.00
Tax (15%): 3.23
- - - - - - - - - - - - - - -
TOTAL: 24.73
------------------------------------------------
Thank you for your purchase!
شكرا لزيارتكم
[QR CODE]
||||| BARCODE |||||
001234
Simple Receipt (minimal) #
For a quick receipt without store info:
final cmd = EscPosCommands(PaperSize.mm80);
cmd.initialize();
SimpleReceipt.print(
cmd,
title: 'RECEIPT',
items: [
ReceiptItem(name: 'Item A', quantity: 2, price: 10.0),
ReceiptItem(name: 'Item B', quantity: 1, price: 25.0),
],
cutAfter: true,
);
await printer.sendBytes(cmd.getBytes());
Custom Receipt (build your own) #
You can build any layout using the low-level commands:
final cmd = EscPosCommands(PaperSize.mm80);
cmd.initialize();
cmd.setCodePage(CodePage.win1256);
// Header
cmd.textStyled('INVOICE',
PosStyles(align: PrintAlign.center, bold: true, width: 2, height: 2),
useLatin: true);
cmd.textStyled('My Company LLC',
PosStyles(align: PrintAlign.center),
useLatin: true);
cmd.hr(style: LineStyle.doubleLine);
// Items
cmd.row([
PosColumn(text: 'Description', width: 6),
PosColumn(text: 'Qty', width: 2, align: PrintAlign.center),
PosColumn(text: 'Amount', width: 4, align: PrintAlign.right),
], useLatin: true);
cmd.hr(style: LineStyle.dashed);
cmd.row([
PosColumn(text: 'Laptop', width: 6),
PosColumn(text: '1', width: 2, align: PrintAlign.center),
PosColumn(text: '999.00', width: 4, align: PrintAlign.right),
], useLatin: true);
cmd.hr(style: LineStyle.doubleLine);
// Total
cmd.setBold(true);
cmd.setFontSize(2, 1);
cmd.leftRight('TOTAL:', '\$999.00', useLatin: true);
cmd.resetStyles();
// Arabic footer
cmd.setAlign(PrintAlign.center);
cmd.textLn('شكرا لك');
cmd.setAlign(PrintAlign.left);
// QR code
cmd.printQrCode('https://mycompany.com/inv/12345', size: 5);
cmd.feedAndCut();
await printer.sendBytes(cmd.getBytes());
15. Paper Cut, Cash Drawer & Beep #
Paper Cut #
cmd.cut(); // Full cut
cmd.cut(mode: CutMode.partial); // Partial cut (leaves a small strip)
cmd.feedAndCut(); // Feed 3 lines + full cut
cmd.feedAndCut(lines: 5, mode: CutMode.partial); // Custom
Cash Drawer #
cmd.openDrawer(); // Open via pin 2 (default)
cmd.openDrawer(pin: DrawerPin.pin5); // Open via pin 5
Beep #
cmd.beep(); // Single beep
cmd.beep(count: 3, duration: 5); // 3 beeps, each 5 units long
Paper Feed #
cmd.feed(1); // Feed 1 line
cmd.feed(5); // Feed 5 lines
cmd.newLine(); // Single line feed
16. Full API Reference #
ThermalPrinterManager #
| Method | Description |
|---|---|
ensureReady() |
One-call setup: permissions + Bluetooth enable |
requestPermissions() |
Request Bluetooth permissions (shows system dialog) |
checkPermissions() |
Check which permissions are granted |
isBluetoothEnabled() |
Check if Bluetooth is turned on |
enableBluetooth() |
Show system dialog to enable Bluetooth |
getBondedDevices() |
Get list of already-paired Bluetooth devices |
startScan() |
Start discovering nearby Bluetooth devices |
stopScan() |
Stop scanning |
connect(address) |
Connect to a printer by MAC address |
connectWithRetry(address) |
Connect with automatic retry on failure |
disconnect() |
Disconnect from current printer |
sendBytes(Uint8List) |
Send raw bytes to the printer |
checkConnected() |
Check if still connected |
setProtocol(String) |
Set MFi protocol string (iOS only) |
scanResults |
Stream of discovered devices |
connectionState |
Stream of connection state changes |
isConnected |
Current connection status |
dispose() |
Release resources |
EscPosCommands #
| Method | Description |
|---|---|
initialize() |
Reset printer to defaults (ESC @) |
resetStyles() |
Reset text formatting only |
setCodePage(CodePage) |
Set code page from preset |
setCodePageRaw(int) |
Set code page by raw number |
setCodePageFromString(String) |
Parse code page from string |
setCharSet(CharSet) |
Set international character set |
setBold(bool) |
Bold on/off |
setUnderline(int) |
0=off, 1=single, 2=double |
setFontSize(w, h) |
Size multiplier 1-8 |
setAlign(PrintAlign) |
Left, center, right |
setFont(FontType) |
Font A or B |
setReverse(bool) |
White on black |
setUpsideDown(bool) |
Upside down text |
setLineSpacing(int) |
Line spacing in dots |
resetLineSpacing() |
Reset to default spacing |
setCharSpacing(int) |
Character spacing in dots |
setDensity(int) |
Print darkness 0-15 |
text(String) |
Print text (no line feed) |
textLn(String) |
Print text + line feed |
textStyled(String, PosStyles) |
Print with styles (auto-resets) |
newLine() |
Print blank line |
writeRaw(String) |
Write raw code units |
rawBytes(Uint8List) |
Write raw bytes |
row(List<PosColumn>) |
Multi-column row |
leftRight(left, right) |
Left-right aligned text |
hr() |
Horizontal line |
feed(int) |
Feed n lines |
cut() |
Cut paper |
feedAndCut() |
Feed + cut |
openDrawer() |
Open cash drawer |
beep() |
Buzzer beep |
printImage(Uint8List) |
Print image |
printRasterImage(...) |
Print pre-processed image |
printQrCode(String) |
Print QR code |
printBarcode(String, BarcodeType) |
Print barcode |
getBytes() |
Get buffered bytes + clear |
peekBytes() |
Get bytes without clearing |
clear() |
Clear buffer |
PaperSize #
| Size | Font A Chars | Font B Chars | Max Dot Width |
|---|---|---|---|
PaperSize.mm58 |
32 | 42 | 384 |
PaperSize.mm72 |
42 | 56 | 512 |
PaperSize.mm80 |
48 | 64 | 576 |
PaperSize.mm110 |
66 | 88 | 832 |
17. Distribution Guide #
How to Share This Package #
Option 1: Share the Folder (simplest)
- Copy the
thermal_printer_billbay/folder to anyone who needs it - They put it next to their app folder
- They add to their
pubspec.yaml:dependencies: thermal_printer_billbay: path: ../thermal_printer_billbay - Run
flutter pub get
Option 2: Push to GitHub (recommended for teams)
Step 1: Create a GitHub repo
- Go to https://github.com/new
- Name it
thermal_printer_billbay - Set it to Public or Private
- Do NOT add a README (we already have one)
Step 2: Push your code
Open a terminal in the thermal_printer_billbay/ folder:
cd thermal_printer_billbay
git init
git add .
git commit -m "Initial release v1.0.0"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/thermal_printer_billbay.git
git push -u origin main
Step 3: Create a version tag (optional but recommended)
git tag v1.0.0
git push origin v1.0.0
Step 4: Others can now use it
# In their pubspec.yaml
dependencies:
thermal_printer_billbay:
git:
url: https://github.com/YOUR_USERNAME/thermal_printer_billbay.git
ref: v1.0.0 # or 'main' for latest
Option 3: Publish to pub.dev (public packages)
Step 1: Prepare the package
- Open
thermal_printer_billbay/pubspec.yaml - Remove or change the
publish_to: 'none'line - Make sure
name,description, andversionare set - Make sure this README.md exists and is complete
Step 2: Check the package
cd thermal_printer_billbay
dart pub publish --dry-run
Fix any issues it reports.
Step 3: Create a Google account (if you don't have one)
You need a Google account to publish to pub.dev.
Step 4: Publish
dart pub publish
This will open a browser for Google sign-in, then upload the package.
Step 5: Others can now use it
# In their pubspec.yaml
dependencies:
thermal_printer_billbay: ^1.0.0
Troubleshooting #
"Arabic prints as Chinese/garbage characters" #
Your printer is using the wrong code page. Print a self-test page (hold FEED button while powering on) and find the Arabic code page number. Then use that number:
cmd.setCodePageRaw(YOUR_NUMBER_HERE);
"Cannot find printer" #
- Make sure Bluetooth is turned on
- Make sure the printer is powered on and in pairing mode
- On Android, grant all Bluetooth and Location permissions
- Try pairing the printer first in your phone's Bluetooth settings
"Connection failed" #
- Make sure no other app is connected to the printer
- Turn the printer off and on
- Remove the pairing and re-pair in Bluetooth settings
"Arabic letters are not joined" #
The plugin automatically shapes Arabic text. Make sure you're NOT using useLatin: true for Arabic text:
// WRONG — Arabic won't be shaped
cmd.textLn('مرحبا', useLatin: true);
// CORRECT — Arabic will be shaped automatically
cmd.textLn('مرحبا');
"Image is too dark/light" #
Adjust the threshold value (0=all black, 255=all white):
cmd.printImage(imageBytes, threshold: 100); // Darker
cmd.printImage(imageBytes, threshold: 180); // Lighter
License #
This package is provided as-is for free use. Modify and distribute as needed.