@rejaul/react-native-printer-kit 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +293 -14
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/rejaul/reactnativeprinterkit/ReactNativePrinterKitModule.kt +267 -31
- package/lib/module/NativeReactNativePrinterKit.js +19 -0
- package/lib/module/NativeReactNativePrinterKit.js.map +1 -1
- package/lib/module/enums.js +45 -0
- package/lib/module/enums.js.map +1 -0
- package/lib/module/index.js +107 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeReactNativePrinterKit.d.ts +241 -5
- package/lib/typescript/src/NativeReactNativePrinterKit.d.ts.map +1 -1
- package/lib/typescript/src/enums.d.ts +44 -0
- package/lib/typescript/src/enums.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +73 -7
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeReactNativePrinterKit.ts +280 -5
- package/src/enums.ts +69 -0
- package/src/index.tsx +155 -9
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# react-native-printer-kit
|
|
2
2
|
|
|
3
|
-
A professional-grade React Native module for printing directly to Bluetooth POS/thermal (ESC/POS) printers on **Android devices only** — no third-party printer app, no OS print dialog. Print raw text, images, PDFs, and full HTML/CSS content, including **Bangla and other non-Latin scripts** that ESC/POS printer fonts don't support natively.
|
|
3
|
+
A professional-grade React Native module for printing directly to Bluetooth, Wi-Fi/LAN and USB POS/thermal (ESC/POS) printers on **Android devices only** — no third-party printer app, no OS print dialog. Print raw text, images, PDFs, and full HTML/CSS content, including **Bangla and other non-Latin scripts** that ESC/POS printer fonts don't support natively.
|
|
4
4
|
|
|
5
|
-
> **Important:** This library is **exclusively for Android**. Bluetooth Classic SPP
|
|
5
|
+
> **Important:** This library is **exclusively for Android**. Bluetooth Classic SPP, USB host and ESC/POS are Android-specific integrations; iOS does not expose the APIs this relies on.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@rejaul/react-native-printer-kit)
|
|
8
8
|
[](LICENSE)
|
|
@@ -18,7 +18,11 @@ It's a thin React Native bridge over [`android-printer-kit`](https://github.com/
|
|
|
18
18
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
21
|
-
- **
|
|
21
|
+
- **Three connection types** behind one API: Bluetooth Classic (SPP), Wi-Fi/LAN (raw TCP) and USB (OTG). Every print function is the same for all three.
|
|
22
|
+
- **Printer-only device list**: `getBondedBluetoothPrinters({ filter: 'LIKELY_PRINTERS' })` hides headphones, watches and other non-printers.
|
|
23
|
+
- **Printer checks**: `isPrinterReady()`, `getPrinterStatus()` (online / paper out / cover / error) and `printTestPage()`.
|
|
24
|
+
- **Save files** (e.g. the PDF from `htmlToPdf`) to Downloads, Documents, app storage or a chosen folder with `saveFile()`.
|
|
25
|
+
- **Honest connection notification**: if the printer drops (switched off, out of range, Bluetooth off, USB unplugged) the ongoing "connected" notification is replaced by a dismissible "disconnected" one.
|
|
22
26
|
- **HTML → PDF → print** pipeline, so you can print an actual styled receipt/report.
|
|
23
27
|
- **PDF → image → print** pipeline via Android's built-in `PdfRenderer`.
|
|
24
28
|
- **Non-Latin text support** (Bangla and others) via image-based rendering.
|
|
@@ -36,7 +40,15 @@ It's a thin React Native bridge over [`android-printer-kit`](https://github.com/
|
|
|
36
40
|
|
|
37
41
|
## Scope
|
|
38
42
|
|
|
39
|
-
This library speaks **
|
|
43
|
+
This library speaks **ESC/POS** — the standard used by virtually all receipt/thermal POS printers — over:
|
|
44
|
+
|
|
45
|
+
| Connection | Notes |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Bluetooth Classic (SPP) | The printer must be paired in Android's Bluetooth settings first. |
|
|
48
|
+
| Wi-Fi / LAN | Raw TCP, usually port 9100. Phone and printer must be on the same network; there is no discovery, so you supply the IP. |
|
|
49
|
+
| USB | Needs a phone with USB host (OTG) and the user's per-device permission (`requestUsbPermission`). |
|
|
50
|
+
|
|
51
|
+
Not supported: Bluetooth LE-only printers, label printers that use TSPL/ZPL/CPCL (Zebra, TSC, ...), and non-ESC/POS protocols (PCL/PostScript inkjet & laser printers).
|
|
40
52
|
|
|
41
53
|
## Minimum Requirements
|
|
42
54
|
|
|
@@ -52,7 +64,7 @@ npm install @rejaul/react-native-printer-kit
|
|
|
52
64
|
yarn add @rejaul/react-native-printer-kit
|
|
53
65
|
```
|
|
54
66
|
|
|
55
|
-
Nothing to configure manually — all required Bluetooth and foreground-service permissions are declared by the underlying native library's manifest and merge in automatically. You still need to request the runtime `BLUETOOTH_CONNECT` (Android 12+) and `POST_NOTIFICATIONS` (Android 13+) permissions at runtime — `requestBluetoothPermission()` handles both in one call; see [Permissions](#permissions) below.
|
|
67
|
+
Nothing to configure manually — all required Bluetooth, internet, USB-host and foreground-service permissions are declared by the underlying native library's manifest and merge in automatically. You still need to request the runtime `BLUETOOTH_CONNECT` (Android 12+) and `POST_NOTIFICATIONS` (Android 13+) permissions at runtime — `requestBluetoothPermission()` handles both in one call; see [Permissions](#permissions) below.
|
|
56
68
|
|
|
57
69
|
## Quick Start
|
|
58
70
|
|
|
@@ -117,11 +129,39 @@ Every function that takes data (anything beyond a bare callback) takes a single
|
|
|
117
129
|
|
|
118
130
|
### Connection
|
|
119
131
|
|
|
120
|
-
#### `getBondedBluetoothPrinters(): BluetoothPrinterDevice[]`
|
|
121
|
-
Lists Bluetooth devices already paired with the phone via Android's own Bluetooth settings.
|
|
132
|
+
#### `getBondedBluetoothPrinters(params?: GetBondedPrintersParams): BluetoothPrinterDevice[]`
|
|
133
|
+
Lists Bluetooth devices already paired with the phone via Android's own Bluetooth settings, best printer matches first. Each device has a `confidence` (`CONFIDENT` / `LIKELY` / `UNKNOWN`). Pass `{ filter: 'LIKELY_PRINTERS' }` to hide devices that do not look like printers (`'STRICT'` keeps only certain ones), or `extraNameKeywords: ['part-of-its-name']` if a real printer has an unusual name and gets hidden. With no argument every paired device is returned, as before.
|
|
134
|
+
|
|
135
|
+
#### `getUsbPrinters(): UsbPrinterDevice[]`
|
|
136
|
+
USB printers currently plugged in (devices exposing the USB *printer* class). Needs a phone with USB host (OTG).
|
|
137
|
+
|
|
138
|
+
#### `hasUsbPermission(params: UsbDeviceParams): boolean`
|
|
139
|
+
Whether the user already granted this app access to that USB printer.
|
|
140
|
+
|
|
141
|
+
#### `requestUsbPermission(params: UsbDeviceParams): Promise<boolean>`
|
|
142
|
+
Shows the system USB permission dialog and resolves with the user's answer. Call it before connecting. The grant is lost when the app is reinstalled.
|
|
122
143
|
|
|
123
144
|
#### `connectPrinter(params: ConnectPrinterParams): Promise<boolean>`
|
|
124
|
-
|
|
145
|
+
Connects over Bluetooth (default), Wi-Fi/LAN or USB depending on `params.type`. Closes any existing connection first, and remembers the printer for auto-reconnect on the next app launch. Resolves `false` (does not reject) if it could not connect; for USB that includes a missing permission.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Bluetooth (default) - the printer must be paired first
|
|
149
|
+
await connectPrinter({ address: 'AA:BB:CC:DD:EE:FF' });
|
|
150
|
+
|
|
151
|
+
// Wi-Fi / LAN
|
|
152
|
+
await connectPrinter({ address: '192.168.1.50', type: 'NETWORK', port: 9100 });
|
|
153
|
+
|
|
154
|
+
// USB - ask for permission first (system dialog), then connect
|
|
155
|
+
const usb = getUsbPrinters()[0];
|
|
156
|
+
if (usb && (await requestUsbPermission(usb))) {
|
|
157
|
+
await connectPrinter({
|
|
158
|
+
address: '',
|
|
159
|
+
type: 'USB',
|
|
160
|
+
vendorId: usb.vendorId,
|
|
161
|
+
productId: usb.productId,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
```
|
|
125
165
|
|
|
126
166
|
#### `disconnectPrinter(): Promise<void>`
|
|
127
167
|
Closes the current connection and forgets it for auto-reconnect.
|
|
@@ -132,6 +172,91 @@ Whether a printer connection is currently open.
|
|
|
132
172
|
#### `getConnectedPrinter(): Promise<BluetoothPrinterDevice | null>`
|
|
133
173
|
The currently connected printer, if any.
|
|
134
174
|
|
|
175
|
+
### Printer checks
|
|
176
|
+
|
|
177
|
+
#### `isPrinterReady(): Promise<boolean>`
|
|
178
|
+
Connected **and** the printer accepts data right now (it may be switched off or out of range). It does not check paper or the cover.
|
|
179
|
+
|
|
180
|
+
#### `getPrinterStatus(params?: PrinterStatusParams): Promise<PrinterStatus>`
|
|
181
|
+
Asks the printer for its state. Many printers ignore the request: then `responded` is `false` and every other field is `null` (unknown, **not** "ok"). Things to know:
|
|
182
|
+
|
|
183
|
+
- Right after connecting, the first request can time out (`responded: false`); asking again a moment later works.
|
|
184
|
+
- What a printer reports depends on its firmware. On the USB receipt printer used for testing, an open cover was reported as `online: false, paperOut: true` and never as `coverOpen: true`. So read `paperOut: true` as "no paper *or* cover open", and do not rely on `coverOpen` unless you verified it on your printer model.
|
|
185
|
+
- `online: false` is the most reliable "do not print now" signal.
|
|
186
|
+
- A print call that resolves only means the bytes were sent. An offline or out-of-paper printer may still accept them, so check the status first when it matters.
|
|
187
|
+
|
|
188
|
+
#### `printTestPage(): Promise<void>`
|
|
189
|
+
Prints a short ASCII test page (connection type, printer, address, time).
|
|
190
|
+
|
|
191
|
+
### Saving and opening files
|
|
192
|
+
|
|
193
|
+
#### `saveFile(params: SaveFileParams): Promise<SaveFileResult>`
|
|
194
|
+
Saves a file to `CACHE`, `APP_FILES`, public `DOWNLOADS` / `DOCUMENTS`, the public `PICTURES` folder (shows in the Gallery; images only) or a `CUSTOM_FOLDER`. Either copy an existing file with `sourcePath` (for example the PDF from `htmlToPdf`), or **pass the content directly**: `text` (UTF-8 string) or `base64` (bytes, for images/PDFs; a `data:...;base64,` prefix is fine). Give exactly one of the three; with `text` / `base64` a `fileName` is required. Never rejects: check `result.success` and `result.error`.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
await saveFile({ text: csv, fileName: 'report.csv', subFolder: 'MyApp' });
|
|
198
|
+
await saveFile({ base64: pngBase64, fileName: 'qr.png', location: FileLocation.DOCUMENTS });
|
|
199
|
+
``` On Android 10+ Downloads/Documents use MediaStore (no permission needed); on Android 9 and below you need `WRITE_EXTERNAL_STORAGE`. `overwrite: true` can only replace files this app created.
|
|
200
|
+
|
|
201
|
+
#### `readFile(params: ReadFileParams): Promise<ReadFileResult>`
|
|
202
|
+
Reads **one** file and returns its content in the shape `format` asks for. `path` is an absolute path, or the `content://` Uri that `saveFile` returned.
|
|
203
|
+
|
|
204
|
+
| `format` | `result` holds |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `'base64'` (default) | `content`: plain base64, for images, PDFs and any binary file |
|
|
207
|
+
| `'dataUri'` | `content`: `data:<type>;base64,...` (type from the file extension), ready for an `<Image>`/`<img>` or an upload |
|
|
208
|
+
| `'text'` | `content`: the file decoded as text (UTF-8, or `encoding: 'UTF-16'`, `'ISO-8859-1'`, ...). Only meaningful for text files |
|
|
209
|
+
| `'hex'` | `content`: lower-case hex, two digits per byte |
|
|
210
|
+
| `'bytes'` | `bytes`: array of numbers 0–255. Heavy, so **capped at 1 MB** |
|
|
211
|
+
|
|
212
|
+
Also returned: `sizeBytes` and `mimeType`. The whole file is loaded into memory, so a file over `maxBytes` (default **10 MB**) is refused with a clear message instead. Never rejects: check `result.success` and `result.error`. For JSON, read it as `'text'` and `JSON.parse` it.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const r = await readFile({ path: imagePath, format: 'base64' });
|
|
216
|
+
if (r.success) await upload(r.content!); // "iVBORw0KGgo..."
|
|
217
|
+
|
|
218
|
+
const pdf = await readFile({ path: pdfPath, format: 'dataUri' });
|
|
219
|
+
// pdf.content = "data:application/pdf;base64,JVBERi0x..."
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### `htmlToImage(params: HtmlToImageParams): Promise<string | null>`
|
|
223
|
+
Renders HTML to **one** image file and returns its path, or `null` on failure. It is `htmlToPdf` plus one rendered page: `imageType` is `'PNG'` (default) or `'JPEG'`, `targetWidthPx` is the image width (default: twice the page width), `outputPath` chooses the full file path (folder must exist), and `pageWidthDp` / `heightDp` / `minPageHeightDp` work as in `htmlToPdf`. A **very tall page makes a very large bitmap and can run out of memory**, in which case you get `null`. For base64, pass the returned path to `readFile`.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const png = await htmlToImage({ html: receiptHtml, targetWidthPx: 800 });
|
|
227
|
+
if (png) {
|
|
228
|
+
const b64 = await readFile({ path: png, format: 'base64' }); // send to your server
|
|
229
|
+
await saveFile({ sourcePath: png, fileName: 'receipt.png', location: FileLocation.PICTURES }); // Gallery
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `readDir(params: ReadDirParams): Promise<ReadDirResult>`
|
|
234
|
+
Reads **one** folder: the files and folders directly inside it, **folders first, then A–Z**. `path` is an absolute folder path, or the `content://` Uri of a folder the user picked with the system folder picker. `result.names` is just the names; `result.entries` has `name`, `path`, `isDirectory`, `sizeBytes` (`null` for a folder) and `lastModified`. It does not go into sub-folders: call it again with an entry's `path` to go deeper, and an entry's `path` also works with `removeFile`. A path that is a file, is missing or is relative is refused. Android 10+ restricts reading public folders such as Downloads, so for those the result may say the folder cannot be read; the app's own folders and a folder picked with the system folder picker always work. Never rejects: check `result.success` and `result.error`.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const dir = await readDir({ path: '/data/user/0/<your.app>/files' });
|
|
238
|
+
if (dir.success) {
|
|
239
|
+
console.log(dir.names); // ['reports', 'logo.png', 'notes.txt']
|
|
240
|
+
const folders = dir.entries.filter((e) => e.isDirectory);
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### `removeFile(params: RemoveFileParams): Promise<RemoveFileResult>`
|
|
245
|
+
Deletes **one** file: an absolute `path`, or the `content://` Uri that `saveFile` returned. It never deletes a folder, never expands a pattern, refuses a relative path, and **cannot be undone**. A missing file is reported as a failure (`"File not found"`), which you can ignore if you only wanted it gone. On Android 10+ a file in Downloads/Documents (a MediaStore Uri) can only be deleted if your app created it. Never rejects: check `result.success` and `result.error`.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const saved = await saveFile({ text: 'temp', fileName: 'tmp.txt' });
|
|
249
|
+
if (saved.success) await removeFile({ path: saved.path ?? saved.uri! });
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### `openFile(params: OpenFileParams): boolean`
|
|
253
|
+
Opens a file with whatever installed app can handle its type (shows the "Open with" chooser if several match). Returns `false` if the file does not exist or no app can open it.
|
|
254
|
+
|
|
255
|
+
### Bluetooth state
|
|
256
|
+
|
|
257
|
+
#### `isBluetoothEnabled(): boolean`
|
|
258
|
+
Whether the Bluetooth adapter itself is on. Needs no runtime permission, so check it before asking for the permission.
|
|
259
|
+
|
|
135
260
|
### Printing
|
|
136
261
|
|
|
137
262
|
#### `printText(params: PrintTextParams): Promise<void>`
|
|
@@ -150,22 +275,171 @@ Renders one PDF page to an image file and returns its path.
|
|
|
150
275
|
`pdfToImage` + print, in one call.
|
|
151
276
|
|
|
152
277
|
#### `htmlToPdf(params: HtmlToPdfParams): Promise<string | null>`
|
|
153
|
-
Renders HTML to a PDF file using an off-screen `WebView` and returns its path, or `null` on failure. `pageWidthDp` controls how large the content renders (like a CSS viewport width), independent of the final printed width. Leave `heightDp` unset to auto-measure the real content height (recommended).
|
|
278
|
+
Renders HTML to a PDF file using an off-screen `WebView` and returns its path, or `null` on failure. Pass `outputPath` (the full path including the file name, e.g. `/data/user/0/<your.app>/files/invoice.pdf`) to choose where the PDF goes; without it you get a generated name in the app's cache folder. `outputPath` must be in a folder that already exists and that your app can write to (its own files/cache folders), and an existing file is overwritten. To end up in a public folder such as Downloads, convert first and then call [`saveFile`](#savefileparams-savefileparams-promisesavefileresult), which accepts `fileName`, `location` and `subFolder`. `pageWidthDp` controls how large the content renders (like a CSS viewport width), independent of the final printed width. Leave `heightDp` unset to auto-measure the real content height (recommended).
|
|
154
279
|
|
|
155
280
|
#### `printHtml(params: PrintHtmlParams): Promise<boolean>`
|
|
156
281
|
Full pipeline: `htmlToPdf` → `printPdf`. This is how you print Bangla (or other non-Latin) text or any real HTML/CSS layout. Retries once (reconnect + resend) if the underlying write fails, e.g. from a "Broken pipe" when a cheap board drops the link mid-print.
|
|
157
282
|
|
|
283
|
+
## Enums
|
|
284
|
+
|
|
285
|
+
The string options are also exported as constants, so you can write `PrinterFilter.LIKELY_PRINTERS` instead of a bare string (plain strings keep working too). Each name is both a runtime value and a type:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import {
|
|
289
|
+
PrinterFilter, // ALL | LIKELY_PRINTERS | STRICT
|
|
290
|
+
PrinterConfidence, // CONFIDENT | LIKELY | UNKNOWN
|
|
291
|
+
PrinterConnectionType, // BLUETOOTH | NETWORK | USB
|
|
292
|
+
PrinterImageType, // PNG | JPEG
|
|
293
|
+
FileLocation, // CACHE | APP_FILES | DOWNLOADS | DOCUMENTS | PICTURES | CUSTOM_FOLDER
|
|
294
|
+
ReadFileFormat, // base64 | dataUri | text | hex | bytes
|
|
295
|
+
} from '@rejaul/react-native-printer-kit';
|
|
296
|
+
|
|
297
|
+
getBondedBluetoothPrinters({ filter: PrinterFilter.LIKELY_PRINTERS });
|
|
298
|
+
connectPrinter({ address: '192.168.1.50', type: PrinterConnectionType.NETWORK });
|
|
299
|
+
saveFile({ sourcePath, location: FileLocation.DOWNLOADS });
|
|
300
|
+
```
|
|
301
|
+
|
|
158
302
|
## Type Definitions
|
|
159
303
|
|
|
160
304
|
```typescript
|
|
305
|
+
type PrinterConfidence = 'CONFIDENT' | 'LIKELY' | 'UNKNOWN';
|
|
306
|
+
type PrinterFilter = 'ALL' | 'LIKELY_PRINTERS' | 'STRICT';
|
|
307
|
+
type PrinterConnectionType = 'BLUETOOTH' | 'NETWORK' | 'USB';
|
|
308
|
+
|
|
161
309
|
type BluetoothPrinterDevice = {
|
|
310
|
+
name: string | null; // null for a Wi-Fi/LAN printer
|
|
311
|
+
address: string; // MAC, host, or "vendorId:productId" for USB
|
|
312
|
+
confidence: PrinterConfidence;
|
|
313
|
+
reason: string | null;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
type GetBondedPrintersParams = {
|
|
317
|
+
filter?: PrinterFilter; // default 'ALL'
|
|
318
|
+
extraNameKeywords?: string[];
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
type UsbPrinterDevice = {
|
|
162
322
|
name: string | null;
|
|
163
|
-
|
|
323
|
+
vendorId: number;
|
|
324
|
+
productId: number;
|
|
325
|
+
deviceName: string;
|
|
164
326
|
};
|
|
165
327
|
|
|
328
|
+
type UsbDeviceParams = { vendorId: number; productId: number };
|
|
329
|
+
|
|
166
330
|
type PrinterImageType = 'PNG' | 'JPEG';
|
|
167
331
|
|
|
168
|
-
type ConnectPrinterParams = {
|
|
332
|
+
type ConnectPrinterParams = {
|
|
333
|
+
address: string; // Bluetooth MAC, or IP/host for NETWORK; '' for USB
|
|
334
|
+
type?: PrinterConnectionType; // default 'BLUETOOTH'
|
|
335
|
+
port?: number; // NETWORK only, default 9100
|
|
336
|
+
timeoutMs?: number; // NETWORK connect timeout, default 5000
|
|
337
|
+
vendorId?: number; // USB only
|
|
338
|
+
productId?: number; // USB only
|
|
339
|
+
notificationTitle?: string; // default 'Printer connected'
|
|
340
|
+
disconnectedNotificationTitle?: string; // default 'Printer disconnected'
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
type PrinterStatusParams = { timeoutMs?: number }; // default 800
|
|
344
|
+
|
|
345
|
+
// null = unknown (the printer did not report it), NOT "ok"
|
|
346
|
+
type PrinterStatus = {
|
|
347
|
+
connected: boolean;
|
|
348
|
+
responded: boolean;
|
|
349
|
+
online: boolean | null;
|
|
350
|
+
paperOut: boolean | null;
|
|
351
|
+
paperNearEnd: boolean | null;
|
|
352
|
+
coverOpen: boolean | null;
|
|
353
|
+
hasError: boolean | null;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
type FileLocation =
|
|
357
|
+
| 'CACHE'
|
|
358
|
+
| 'APP_FILES'
|
|
359
|
+
| 'DOWNLOADS'
|
|
360
|
+
| 'DOCUMENTS'
|
|
361
|
+
| 'PICTURES' // public Pictures folder: shows in the Gallery. Images only.
|
|
362
|
+
| 'CUSTOM_FOLDER';
|
|
363
|
+
|
|
364
|
+
type SaveFileParams = {
|
|
365
|
+
sourcePath?: string; // an existing file ... OR text / base64 below (exactly one)
|
|
366
|
+
text?: string; // content as UTF-8 text; needs fileName
|
|
367
|
+
base64?: string; // content as base64 bytes; needs fileName
|
|
368
|
+
fileName?: string; // defaults to the source file's name; required with text/base64
|
|
369
|
+
location?: FileLocation; // default 'DOWNLOADS'
|
|
370
|
+
customFolder?: string; // required for CUSTOM_FOLDER
|
|
371
|
+
subFolder?: string;
|
|
372
|
+
mimeType?: string; // guessed from the extension
|
|
373
|
+
overwrite?: boolean;
|
|
374
|
+
deleteSource?: boolean;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
type SaveFileResult = {
|
|
378
|
+
success: boolean;
|
|
379
|
+
path: string | null;
|
|
380
|
+
uri: string | null;
|
|
381
|
+
fileName: string | null;
|
|
382
|
+
error: string | null;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
type ReadFileFormat = 'base64' | 'dataUri' | 'text' | 'hex' | 'bytes';
|
|
386
|
+
|
|
387
|
+
type ReadFileParams = {
|
|
388
|
+
path: string; // absolute path, or a content:// Uri
|
|
389
|
+
format?: ReadFileFormat; // default 'base64'
|
|
390
|
+
encoding?: string; // 'text' only; default 'UTF-8'
|
|
391
|
+
maxBytes?: number; // default 10 MB; 'bytes' is always capped at 1 MB
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
type ReadFileResult = {
|
|
395
|
+
success: boolean;
|
|
396
|
+
format: ReadFileFormat | null;
|
|
397
|
+
content: string | null; // base64 / dataUri / text / hex
|
|
398
|
+
bytes: number[] | null; // bytes
|
|
399
|
+
sizeBytes: number | null;
|
|
400
|
+
mimeType: string | null;
|
|
401
|
+
error: string | null;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
type HtmlToImageParams = {
|
|
405
|
+
html: string;
|
|
406
|
+
outputPath?: string; // full path incl. file name; default: generated name in the cache folder
|
|
407
|
+
imageType?: PrinterImageType; // default 'PNG'
|
|
408
|
+
targetWidthPx?: number; // default: twice the page width
|
|
409
|
+
pageWidthDp?: number;
|
|
410
|
+
heightDp?: number;
|
|
411
|
+
minPageHeightDp?: number;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
type ReadDirParams = { path: string }; // absolute folder path, or a folder content:// Uri
|
|
415
|
+
|
|
416
|
+
type DirEntry = {
|
|
417
|
+
name: string;
|
|
418
|
+
path: string; // works with removeFile (a file) or readDir (a folder)
|
|
419
|
+
isDirectory: boolean;
|
|
420
|
+
sizeBytes: number | null; // null for a folder
|
|
421
|
+
lastModified: number | null; // ms since 1970
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
type ReadDirResult = {
|
|
425
|
+
success: boolean;
|
|
426
|
+
path: string | null;
|
|
427
|
+
names: string[];
|
|
428
|
+
entries: DirEntry[];
|
|
429
|
+
error: string | null;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
type RemoveFileParams = { path: string }; // absolute path, or a content:// Uri from saveFile
|
|
433
|
+
|
|
434
|
+
type RemoveFileResult = {
|
|
435
|
+
success: boolean;
|
|
436
|
+
path: string | null;
|
|
437
|
+
uri: string | null;
|
|
438
|
+
fileName: string | null;
|
|
439
|
+
error: string | null;
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
type OpenFileParams = { path: string; mimeType?: string };
|
|
169
443
|
|
|
170
444
|
type PrintTextParams = { text: string; feedLines?: number };
|
|
171
445
|
|
|
@@ -203,6 +477,7 @@ type PrintPdfParams = {
|
|
|
203
477
|
|
|
204
478
|
type HtmlToPdfParams = {
|
|
205
479
|
html: string;
|
|
480
|
+
outputPath?: string; // full path incl. file name; default: generated name in the cache folder
|
|
206
481
|
pageWidthDp?: number;
|
|
207
482
|
heightDp?: number;
|
|
208
483
|
minPageHeightDp?: number;
|
|
@@ -221,9 +496,13 @@ type PrintHtmlParams = {
|
|
|
221
496
|
|
|
222
497
|
## Persistent connection & auto-reconnect
|
|
223
498
|
|
|
224
|
-
Connecting through this library keeps the printer connected even if the app is swiped away from Recents — the native side runs a foreground service that outlives the Activity/JS runtime. Every successful `connectPrinter()` call also remembers the
|
|
499
|
+
Connecting through this library keeps the printer connected even if the app is swiped away from Recents — the native side runs a foreground service that outlives the Activity/JS runtime. Every successful `connectPrinter()` call also remembers the printer (connection type, address/IP, port and USB ids), so the next time the app is opened (even after being fully killed) it reconnects automatically without the user having to pick the printer again.
|
|
500
|
+
|
|
501
|
+
`connectPrinter()` falls back to a direct RFCOMM channel if the standard SDP-based socket fails (common on printers with a broken SDP record). `isConnectedPrinter()` reflects a real disconnect for Bluetooth (Android's ACL-disconnect and Bluetooth-off events) and USB (unplugging) instead of a stale flag; a dropped Wi-Fi/LAN link is only noticed on the next write, which reconnects once automatically.
|
|
502
|
+
|
|
503
|
+
## Connection lost notification
|
|
225
504
|
|
|
226
|
-
|
|
505
|
+
When a connected printer drops on its own, the ongoing **"Printer connected"** notification is removed and a normal, dismissible **"Printer disconnected — \<printer name\>"** notification is posted. Reconnecting removes it again. Calling `disconnectPrinter()` yourself shows no notification. Change the wording with `notificationTitle` / `disconnectedNotificationTitle` in `connectPrinter()`.
|
|
227
506
|
|
|
228
507
|
## Printing Bangla / other non-Latin text
|
|
229
508
|
|
|
@@ -231,7 +510,7 @@ ESC/POS printer firmware fonts only cover ASCII, so `printText()` can't render B
|
|
|
231
510
|
|
|
232
511
|
## Example Application
|
|
233
512
|
|
|
234
|
-
See the [`example`](./example) directory for a complete React Native application demonstrating permission handling,
|
|
513
|
+
See the [`example`](./example) directory for a complete React Native application demonstrating permission handling, Bluetooth and USB connection, printer status, the test page, and the print functions above.
|
|
235
514
|
|
|
236
515
|
```bash
|
|
237
516
|
cd example
|
package/android/build.gradle
CHANGED