react-native-bluetooth-escpos-printer-dj
v0.2.4
Published
React-Native plugin for the bluetooth ESC/POS printers.
Downloads
522
Maintainers
Readme
React Native Bluetooth ESC/POS Printer
React Native Bluetooth printing for ESC/POS receipt printers and TSC label printers.
This fork is based on the original React Native Bluetooth ESC/POS printer module.
What You Can Print
| Printer mode | Use for | Module |
| --- | --- | --- |
| ESC/POS | Receipts, invoices, kitchens, cash drawers, QR codes, barcodes | BluetoothEscposPrinter |
| TSC | Shipping labels, product labels, stickers, QR labels, barcode labels | BluetoothTscPrinter |
| Bluetooth | Discovery, pairing, connecting, connection status | BluetoothManager |
Install
npm install <package-name> --saveFor React Native 0.60 and newer, autolinking should handle native setup.
For React Native 0.59 and older:
react-native link <package-name>Manual Android linking path:
include ':react-native-bluetooth-escpos-printer'
project(':react-native-bluetooth-escpos-printer').projectDir =
new File(rootProject.projectDir, '../node_modules/<package-name>/android')dependencies {
implementation project(':react-native-bluetooth-escpos-printer')
}Import
import {
BluetoothManager,
BluetoothEscposPrinter,
BluetoothTscPrinter,
} from '<package-name>';The Happy Path
The safest flow is always:
- Check or enable Bluetooth.
- Scan for devices.
- Parse the returned device JSON.
- Connect by device address.
- Print with ESC/POS or TSC.
async function connectFirstPrinter() {
const enabled = await BluetoothManager.isBluetoothEnabled();
if (!enabled || enabled === 'false') {
await BluetoothManager.enableBluetooth();
}
const scanResult = await BluetoothManager.scanDevices();
const { paired = [], found = [] } = JSON.parse(scanResult);
const printer = paired[0] || found[0];
if (!printer) {
throw new Error('No Bluetooth printer found');
}
await BluetoothManager.connect(printer.address);
return printer;
}On Android, enableBluetooth() resolves with paired devices. On iOS, it resolves null because iOS does not let apps toggle Bluetooth directly.
Bluetooth Manager
| Method | Params | Resolves | Notes |
| --- | --- | --- | --- |
| isBluetoothEnabled() | none | boolean on Android, 'true' or 'false' on iOS | Use loose checks if supporting both platforms. |
| enableBluetooth() | none | paired device array on Android, null on iOS | Android may show the system Bluetooth dialog. |
| disableBluetooth() | none | boolean or null | Android only behavior; iOS resolves null. |
| scanDevices() | none | JSON string { paired, found } | Also emits discovery events. |
| stopScan() | none | null | iOS supported. |
| connect(address) | address: string | null or address | Address is MAC on Android, UUID on iOS. |
| disconnect(address) | address: string | address | Android method. |
| unpaire(address) | address: string | address | Android method. Name is intentionally legacy-spelled in native code. |
| isDeviceConnected() | none | boolean | Android method. |
| getConnectedDeviceAddress() | none | string | Android method. |
Discovery Events
Use DeviceEventEmitter on Android and NativeEventEmitter patterns as needed for your React Native version.
import { DeviceEventEmitter } from 'react-native';
const subscriptions = [
DeviceEventEmitter.addListener(
BluetoothManager.EVENT_DEVICE_ALREADY_PAIRED,
({ devices }) => console.log('paired', JSON.parse(devices)),
),
DeviceEventEmitter.addListener(
BluetoothManager.EVENT_DEVICE_FOUND,
(event) => console.log('found', event),
),
DeviceEventEmitter.addListener(
BluetoothManager.EVENT_CONNECTED,
() => console.log('connected'),
),
DeviceEventEmitter.addListener(
BluetoothManager.EVENT_CONNECTION_LOST,
() => console.log('connection lost'),
),
];
// Later:
subscriptions.forEach((subscription) => subscription.remove());Events exposed by the module:
| Event | Meaning |
| --- | --- |
| EVENT_DEVICE_ALREADY_PAIRED | Previously paired devices were read. |
| EVENT_DEVICE_FOUND | A device was discovered during scan. |
| EVENT_DEVICE_DISCOVER_DONE | Scan finished. |
| EVENT_CONNECTED | Device connected. |
| EVENT_UNABLE_CONNECT | Connection attempt failed. |
| EVENT_CONNECTION_LOST | Active connection was lost. |
| EVENT_BLUETOOTH_NOT_SUPPORT | Android device has no Bluetooth adapter. |
ESC/POS Receipts
Use this for thermal receipt printers.
Receipt Example
async function printReceipt() {
await BluetoothEscposPrinter.printerInit();
await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.CENTER);
await BluetoothEscposPrinter.printText('MY STORE\n\r', {
size: 2,
bold: true,
});
await BluetoothEscposPrinter.printText('Tax Invoice\n\r', {
size: 1,
});
await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.LEFT);
await BluetoothEscposPrinter.printText('Order: #10023\n\r', {});
await BluetoothEscposPrinter.printText('Date: 2026-07-02\n\r', {});
await BluetoothEscposPrinter.printText('--------------------------------\n\r', {});
await BluetoothEscposPrinter.printColumn(
[18, 6, 8],
[
BluetoothEscposPrinter.ALIGN.LEFT,
BluetoothEscposPrinter.ALIGN.CENTER,
BluetoothEscposPrinter.ALIGN.RIGHT,
],
['Item', 'Qty', 'Total'],
{ bold: true },
);
await BluetoothEscposPrinter.printColumn(
[18, 6, 8],
[
BluetoothEscposPrinter.ALIGN.LEFT,
BluetoothEscposPrinter.ALIGN.CENTER,
BluetoothEscposPrinter.ALIGN.RIGHT,
],
['Coffee', '2', '160.00'],
{},
);
await BluetoothEscposPrinter.printText('--------------------------------\n\r', {});
await BluetoothEscposPrinter.printColumn(
[18, 6, 8],
[
BluetoothEscposPrinter.ALIGN.LEFT,
BluetoothEscposPrinter.ALIGN.CENTER,
BluetoothEscposPrinter.ALIGN.RIGHT,
],
['Grand Total', '', '160.00'],
{ bold: true },
);
await BluetoothEscposPrinter.printerAlign(BluetoothEscposPrinter.ALIGN.CENTER);
await BluetoothEscposPrinter.printQRCode(
'https://example.com/order/10023',
220,
BluetoothEscposPrinter.ERROR_CORRECTION.M,
);
if (BluetoothEscposPrinter.printAndFeed) {
await BluetoothEscposPrinter.printAndFeed(3);
} else {
await BluetoothEscposPrinter.printText('\n\r\n\r\n\r', {});
}
}ESC/POS Methods
| Method | Platform | Params | Notes |
| --- | --- | --- | --- |
| printerInit() | Android, iOS | none | Reset/init printer state. Call before a new receipt. |
| printAndFeed(feed) | Android | feed: number | Print buffer and feed paper by lines/dots, depending on printer firmware. |
| printerLeftSpace(sp) | Android, iOS | sp: number | Set left spacing. |
| printerLineSpace(sp) | Android | sp: number | Set line spacing. 0 resets default on Android. |
| printerUnderLine(line) | Android, iOS | 0, 1, 2 | Off, on, thicker underline. |
| printerAlign(align) | Android, iOS | BluetoothEscposPrinter.ALIGN.* | LEFT, CENTER, RIGHT. Does not affect image positioning on some printers. |
| printText(text, options) | Android, iOS | string, EscposTextOptions | Print text. Add \n\r when you want a new line. |
| printColumn(widths, aligns, texts, options) | Android, iOS | arrays plus EscposTextOptions | Arrays must have the same length. |
| setWidth(width) | Android, iOS | 384 or 576 usually | Set printer dot width. 58 mm often uses 384; 80 mm often uses 576. |
| printPic(base64, options) | Android, iOS | base64 without data URI prefix | Print image. |
| setBlob(weight) | Android, iOS | 0 or 1 | Legacy name for bold mode. |
| rotate(value) | Android, iOS | BluetoothEscposPrinter.ROTATION.* | OFF or ON. |
| printQRCode(content, size, correctionLevel) | Android, iOS | string, number, correction level | Prints QR as bitmap. |
| printBarCode(str, type, width, height, hriFontType, hriPosition) | Android, iOS | see constants | Prints 1D barcode. |
| openDrawer(mode, time1, time2) | Android | numbers | Opens cash drawer. |
| cutOnePoint() | Android | none | Sends cut command. |
| selfTest(callback) | Android | callback | Prints self-test. |
ESC/POS Text Options
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| encoding | string | GBK | Use UTF-8 when your printer firmware supports it. |
| codepage | number | 0 | Printer code page. |
| widthtimes | 0..3 | 0 | Width multiplier. |
| heigthtimes | 0..3 | 0 | Height multiplier. Legacy spelling is required. |
| fonttype | number | 0 | Printer font type. iOS also accepts fontType. |
| size | 0..3 | none | Convenience option. Sets widthtimes and heigthtimes unless they are already provided. |
| bold | boolean | none | Convenience option. Enables bold for this call and resets it afterward. |
ESC/POS Constants
BluetoothEscposPrinter.ALIGN.LEFT; // 0
BluetoothEscposPrinter.ALIGN.CENTER; // 1
BluetoothEscposPrinter.ALIGN.RIGHT; // 2
BluetoothEscposPrinter.ERROR_CORRECTION.L; // 1
BluetoothEscposPrinter.ERROR_CORRECTION.M; // 0
BluetoothEscposPrinter.ERROR_CORRECTION.Q; // 3
BluetoothEscposPrinter.ERROR_CORRECTION.H; // 2
BluetoothEscposPrinter.BARCODETYPE.CODE128;
BluetoothEscposPrinter.ROTATION.OFF;
BluetoothEscposPrinter.ROTATION.ON;TSC Labels
Use this for label printers that understand TSC commands.
Label Example
async function printShippingLabel(base64Logo) {
await BluetoothTscPrinter.printLabel({
width: 60,
height: 40,
gap: 2,
speed: BluetoothTscPrinter.PRINT_SPEED.SPEED3,
density: BluetoothTscPrinter.DENSITY.DNESITY8,
direction: BluetoothTscPrinter.DIRECTION.FORWARD,
reference: [0, 0],
tear: BluetoothTscPrinter.TEAR.ON,
sound: 1,
home: 1,
text: [
{
text: 'SHIP TO',
x: 24,
y: 20,
fonttype: BluetoothTscPrinter.FONTTYPE.FONT_2,
rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
xscal: BluetoothTscPrinter.FONTMUL.MUL_1,
yscal: BluetoothTscPrinter.FONTMUL.MUL_1,
bold: true,
},
{
text: 'Customer Name',
x: 24,
y: 55,
fonttype: BluetoothTscPrinter.FONTTYPE.FONT_2,
rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
xscal: BluetoothTscPrinter.FONTMUL.MUL_1,
yscal: BluetoothTscPrinter.FONTMUL.MUL_1,
},
],
barcode: [
{
x: 24,
y: 105,
type: BluetoothTscPrinter.BARCODETYPE.CODE128,
height: 60,
readable: BluetoothTscPrinter.READABLE.EANBLE,
rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
code: 'PKG10023',
wide: 2,
narrow: 1,
},
],
qrcode: [
{
x: 360,
y: 40,
level: BluetoothTscPrinter.EEC.LEVEL_M,
width: 5,
rotation: BluetoothTscPrinter.ROTATION.ROTATION_0,
code: 'PKG10023',
},
],
image: base64Logo
? [
{
x: 24,
y: 170,
mode: BluetoothTscPrinter.BITMAP_MODE.OVERWRITE,
width: 120,
image: base64Logo,
},
]
: [],
});
}printLabel(options)
Top-level options:
| Option | Type | Required | Notes |
| --- | --- | --- | --- |
| width | number | yes | Label width in mm. |
| height | number | yes | Label height in mm. |
| gap | number | no | Gap between labels in mm. Use 0 for gapless media. |
| speed | number | no | Use BluetoothTscPrinter.PRINT_SPEED.*. |
| density | number | no | Use BluetoothTscPrinter.DENSITY.*. |
| direction | number | no | FORWARD or BACKWARD. Defaults to forward. |
| reference | [x, y] | no | Label origin. Defaults to [0, 0]. |
| tear | string | no | BluetoothTscPrinter.TEAR.ON or OFF. |
| sound | 0 or 1 | no | Beep after print. |
| home | 0 or 1 | no | Back-feed and return home before printing. |
| text | array | no | Text blocks. |
| barcode | array | no | 1D barcode blocks. |
| qrcode | array | no | QR blocks. |
| image | array | no | Bitmap blocks. |
| reverse | array | no | Reverse/black-fill areas on Android. iOS currently reads the legacy key revers. |
Text block:
| Option | Type | Notes |
| --- | --- | --- |
| text | string | Text to print. |
| x, y | number | Position in dots. |
| fonttype | string | Use BluetoothTscPrinter.FONTTYPE.*. |
| rotation | number | Use BluetoothTscPrinter.ROTATION.*. |
| xscal, yscal | number | Use BluetoothTscPrinter.FONTMUL.*. |
| bold | boolean | Simulates bold by drawing text with small offsets. |
Barcode block:
| Option | Type | Notes |
| --- | --- | --- |
| x, y | number | Position in dots. |
| type | string | Use BluetoothTscPrinter.BARCODETYPE.*. |
| height | number | Barcode height in dots. |
| readable | 0 or 1 | Human readable text off/on. |
| rotation | number | Use BluetoothTscPrinter.ROTATION.*. |
| code | string | Barcode content. |
| wide | number | Wide bar width. |
| narrow | number | Narrow bar width. |
QR block:
| Option | Type | Notes |
| --- | --- | --- |
| x, y | number | Position in dots. |
| level | string | LEVEL_L, LEVEL_M, LEVEL_Q, or LEVEL_H. |
| width | number | QR module size. |
| rotation | number | Use BluetoothTscPrinter.ROTATION.*. |
| code | string | QR content. |
Image block:
| Option | Type | Notes |
| --- | --- | --- |
| x, y | number | Position in dots. |
| mode | number | OVERWRITE, OR, or XOR. |
| width | number | Target image width in dots. |
| image | string | Base64 image data without data:image/...;base64,. |
Reverse block:
| Option | Type | Notes |
| --- | --- | --- |
| x, y | number | Position in dots. |
| width, height | number | Reverse area size in dots. |
TSC Constants
BluetoothTscPrinter.DIRECTION.FORWARD;
BluetoothTscPrinter.DIRECTION.BACKWARD;
BluetoothTscPrinter.TEAR.ON;
BluetoothTscPrinter.TEAR.OFF;
BluetoothTscPrinter.PRINT_SPEED.SPEED1DIV5;
BluetoothTscPrinter.PRINT_SPEED.SPEED2;
BluetoothTscPrinter.PRINT_SPEED.SPEED3;
BluetoothTscPrinter.PRINT_SPEED.SPEED4;
BluetoothTscPrinter.DENSITY.DNESITY0;
BluetoothTscPrinter.DENSITY.DNESITY8;
BluetoothTscPrinter.DENSITY.DNESITY15;
BluetoothTscPrinter.FONTTYPE.FONT_1;
BluetoothTscPrinter.FONTTYPE.FONT_2;
BluetoothTscPrinter.FONTTYPE.SIMPLIFIED_CHINESE;
BluetoothTscPrinter.ROTATION.ROTATION_0;
BluetoothTscPrinter.ROTATION.ROTATION_90;
BluetoothTscPrinter.ROTATION.ROTATION_180;
BluetoothTscPrinter.ROTATION.ROTATION_270;
BluetoothTscPrinter.FONTMUL.MUL_1;
BluetoothTscPrinter.FONTMUL.MUL_2;
BluetoothTscPrinter.BARCODETYPE.CODE128;
BluetoothTscPrinter.EEC.LEVEL_M;
BluetoothTscPrinter.BITMAP_MODE.OVERWRITE;
BluetoothTscPrinter.READABLE.EANBLE;
BluetoothTscPrinter.READABLE.DISABLE;Note: DNESITY and EANBLE keep the native module's legacy spellings for backward compatibility.
Base64 Images
Pass raw base64 only:
const rawBase64 = dataUri.replace(/^data:image\/\w+;base64,/, '');
await BluetoothEscposPrinter.printPic(rawBase64, { width: 384, left: 0 });Common receipt widths:
| Paper | Width |
| --- | --- |
| 58 mm | 384 dots |
| 80 mm | 576 dots |
Android Permissions
Add Bluetooth permissions required by your target SDK. Modern Android versions may require both classic Bluetooth and runtime permissions.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />Request runtime permissions in your app before scanning on Android 6+ and especially Android 12+.
iOS Notes
Add the Bluetooth usage description to your app plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app connects to Bluetooth printers.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app connects to Bluetooth printers.</string>iOS uses BLE peripheral UUIDs as addresses, not Android MAC addresses.
Troubleshooting
| Problem | What to check |
| --- | --- |
| COMMAND_NOT_SEND | Printer is not connected, disconnected during write, or does not support the command. |
| Scan returns no devices on Android | Runtime location/Bluetooth permissions, Bluetooth enabled, printer discoverable. |
| Text prints as boxes | Try encoding: 'GBK', correct codepage, or confirm printer font/codepage support. |
| Image is too wide | Use setWidth(384) for 58 mm or setWidth(576) for 80 mm, then pass matching image width. |
| Columns wrap badly | Keep total column width under printable character width: about 32 for 58 mm, 48 for 80 mm. |
| iOS cannot connect by MAC address | Use the UUID returned by scanDevices() on iOS. |
| Drawer does not open | openDrawer() requires ESC/POS printer hardware wired to a cash drawer port. |
Development
npm install
cd examples && npm install
cd examples && npm start
cd examples && npm test
cd examples/android && ./gradlew assembleDebugThe root npm test script is a placeholder. Use the example app for JavaScript tests.
Publish
npm publish --access publicIf npm reports cache ownership errors:
sudo chown -R "$(id -u):$(id -g)" "$HOME/.npm"License
MIT
