@dimer47/capacitor-plugin-printer 2.0.0
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/CapacitorPluginPrinter.podspec +17 -0
- package/LICENSE +202 -0
- package/Package.swift +31 -0
- package/README.md +505 -0
- package/android/build.gradle +68 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintAdapter.kt +73 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintContent.kt +78 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintIO.kt +136 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintManager.kt +219 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintOptions.kt +260 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintProxy.kt +44 -0
- package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrinterPlugin.kt +267 -0
- package/dist/esm/definitions.d.ts +307 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +13 -0
- package/dist/esm/web.js +47 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +61 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +64 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/PrinterPlugin/PrinterControllerHelper.swift +33 -0
- package/ios/Sources/PrinterPlugin/PrinterFont.swift +99 -0
- package/ios/Sources/PrinterPlugin/PrinterInfo.swift +64 -0
- package/ios/Sources/PrinterPlugin/PrinterItem.swift +104 -0
- package/ios/Sources/PrinterPlugin/PrinterLayout.swift +61 -0
- package/ios/Sources/PrinterPlugin/PrinterPaper.swift +71 -0
- package/ios/Sources/PrinterPlugin/PrinterPlugin.swift +327 -0
- package/ios/Sources/PrinterPlugin/PrinterRenderer.swift +135 -0
- package/ios/Sources/PrinterPlugin/PrinterUnit.swift +45 -0
- package/package.json +75 -0
package/README.md
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
# 🖨️ Capacitor Plugin Printer
|
|
2
|
+
|
|
3
|
+
        
|
|
4
|
+
|
|
5
|
+
A [Capacitor](https://capacitorjs.com) plugin to print HTML, PDF, images, and plain text on iOS, Android, and Web.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Printer } from '@dimer47/capacitor-plugin-printer';
|
|
9
|
+
|
|
10
|
+
await Printer.printHtml({ html: '<b>Hello Capacitor!</b>' });
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**⚠️ Warning:** Version 2.0 introduces breaking changes (migration from Cordova to Capacitor 8, new dedicated print methods, Swift + Kotlin rewrite). If you were using version 1.x, please review the new API below.
|
|
14
|
+
|
|
15
|
+
## 🎉 Features
|
|
16
|
+
|
|
17
|
+
- 📄 Print **HTML & CSS** with full styling support
|
|
18
|
+
- 📝 Print **plain text** with font customization
|
|
19
|
+
- 📑 Print **PDF documents** from file paths or URIs
|
|
20
|
+
- 🖼️ Print **images** (PNG, JPEG, GIF, BMP, HEIF)
|
|
21
|
+
- 🔐 Print **base64-encoded** data with explicit MIME types
|
|
22
|
+
- 🌐 Print the current **WebView** content
|
|
23
|
+
- 📐 **Paper sizes** — named sizes (A0–A10, Letter, Legal, Tabloid, etc.) and custom dimensions
|
|
24
|
+
- 📏 **Unit support** — points, inches, millimeters, centimeters
|
|
25
|
+
- 🎨 **Headers & footers** with labels, page numbers, and font styling (iOS)
|
|
26
|
+
- 🖨️ **Direct print** to a specific printer without dialog (iOS)
|
|
27
|
+
- ✂️ **Duplex** printing (double-sided)
|
|
28
|
+
|
|
29
|
+
## 📍 Supported Platforms
|
|
30
|
+
|
|
31
|
+
| Platform | Version |
|
|
32
|
+
|:---------|:--------|
|
|
33
|
+
| iOS | 15+ |
|
|
34
|
+
| Android | 7.0+ (API 24) |
|
|
35
|
+
| Web | Modern browsers |
|
|
36
|
+
|
|
37
|
+
## 📦 Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @dimer47/capacitor-plugin-printer
|
|
41
|
+
npx cap sync
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 🧮 API
|
|
45
|
+
|
|
46
|
+
### Methods
|
|
47
|
+
|
|
48
|
+
| Method | Description |
|
|
49
|
+
|:-------|:-----------|
|
|
50
|
+
| [`print()`](#-print) | Print content with auto-detected type |
|
|
51
|
+
| [`printHtml()`](#-printhtml) | Print an HTML string |
|
|
52
|
+
| [`printPdf()`](#-printpdf) | Print a PDF from a file path or URI |
|
|
53
|
+
| [`printBase64()`](#-printbase64) | Print base64-encoded data |
|
|
54
|
+
| [`printFile()`](#-printfile) | Print a file from a path or URI |
|
|
55
|
+
| [`printWebView()`](#-printwebview) | Print the current WebView content |
|
|
56
|
+
| [`canPrintItem()`](#-canprintitem) | Check if the device can print |
|
|
57
|
+
| [`getPrintableTypes()`](#-getprintabletypes) | List supported printable document types |
|
|
58
|
+
| [`pick()`](#-pick) | Show the printer picker (iOS only) |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### 📄 print()
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
print(options?: PrintOptions) => Promise<PrintResult>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Print content with automatic type detection. The plugin detects whether the content is HTML, a file URI, base64 data, or plain text.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// HTML
|
|
72
|
+
await Printer.print({ content: '<h1>Hello</h1>' });
|
|
73
|
+
|
|
74
|
+
// File
|
|
75
|
+
await Printer.print({ content: 'file:///path/to/document.pdf' });
|
|
76
|
+
|
|
77
|
+
// Base64
|
|
78
|
+
await Printer.print({ content: 'base64://JVBERi0...' });
|
|
79
|
+
|
|
80
|
+
// Plain text
|
|
81
|
+
await Printer.print({ content: 'Hello World' });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### 📄 printHtml()
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
printHtml(options: PrintHtmlOptions) => Promise<PrintResult>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Print an HTML string.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
await Printer.printHtml({
|
|
96
|
+
html: '<h1>Invoice</h1><p>Amount: $42.00</p>',
|
|
97
|
+
name: 'Invoice',
|
|
98
|
+
orientation: 'portrait',
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### 📑 printPdf()
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
printPdf(options: PrintPdfOptions) => Promise<PrintResult>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Print a PDF file from a path or URI.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
await Printer.printPdf({ path: 'file:///path/to/document.pdf' });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### 🔐 printBase64()
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
printBase64(options: PrintBase64Options) => Promise<PrintResult>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Print base64-encoded data with an explicit MIME type.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
await Printer.printBase64({
|
|
128
|
+
data: 'JVBERi0xLjQK...', // base64 string without prefix
|
|
129
|
+
mimeType: 'application/pdf',
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### 🖼️ printFile()
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
printFile(options: PrintFileOptions) => Promise<PrintResult>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Print a file from a path or URI. The MIME type is detected automatically if not provided.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
await Printer.printFile({ path: 'file:///path/to/image.png' });
|
|
145
|
+
|
|
146
|
+
// With explicit MIME type
|
|
147
|
+
await Printer.printFile({
|
|
148
|
+
path: 'file:///path/to/doc',
|
|
149
|
+
mimeType: 'application/pdf',
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### 🌐 printWebView()
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
printWebView(options?: PrintWebViewOptions) => Promise<PrintResult>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Print the current WebView content.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
await Printer.printWebView();
|
|
165
|
+
|
|
166
|
+
// With options
|
|
167
|
+
await Printer.printWebView({ orientation: 'landscape' });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### ✅ canPrintItem()
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
canPrintItem(options?: CanPrintOptions) => Promise<CanPrintResult>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Check if the device supports printing, optionally for a specific item.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const { available } = await Printer.canPrintItem();
|
|
182
|
+
|
|
183
|
+
// Check a specific URI
|
|
184
|
+
const { available } = await Printer.canPrintItem({ uri: 'file:///path/to/file.pdf' });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### 📋 getPrintableTypes()
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
getPrintableTypes() => Promise<PrintableTypesResult>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Get the list of printable document types supported by the platform (UTIs on iOS, MIME types on Android).
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const { types } = await Printer.getPrintableTypes();
|
|
199
|
+
// e.g. ["com.adobe.pdf", "public.jpeg", "public.png", ...]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### 🖨️ pick()
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
pick(options?: PickOptions) => Promise<PickResult>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Show the system printer picker. **iOS only** — on Android, this method will reject.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const { url } = await Printer.pick();
|
|
214
|
+
if (url) {
|
|
215
|
+
await Printer.printHtml({ html: '<p>Direct print</p>', printer: url });
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## ⚙️ Options
|
|
222
|
+
|
|
223
|
+
### BasePrintOptions
|
|
224
|
+
|
|
225
|
+
Common options shared by all print methods.
|
|
226
|
+
|
|
227
|
+
| Property | Type | Default | Platform | Description |
|
|
228
|
+
|:---------|:-----|:--------|:---------|:------------|
|
|
229
|
+
| `name` | `string` | — | All | Job name and document title |
|
|
230
|
+
| `orientation` | `'portrait' \| 'landscape'` | `'portrait'` | All | Print orientation |
|
|
231
|
+
| `monochrome` | `boolean` | `false` | All | Black & white printing |
|
|
232
|
+
| `photo` | `boolean` | `false` | iOS | Photography media type for higher quality |
|
|
233
|
+
| `copies` | `number` | `1` | iOS | Number of copies |
|
|
234
|
+
| `pageCount` | `number` | — | iOS, Android | Maximum number of pages to print |
|
|
235
|
+
| `duplex` | `'none' \| 'long' \| 'short'` | `'none'` | All | Double-sided printing |
|
|
236
|
+
| `margin` | `boolean \| MarginOptions` | — | All | Margins. Set to `false` to disable |
|
|
237
|
+
| `font` | `FontOptions` | — | iOS | Font configuration for plain text |
|
|
238
|
+
| `maxWidth` | `string \| number` | — | iOS | Maximum content width |
|
|
239
|
+
| `maxHeight` | `string \| number` | — | iOS | Maximum content height |
|
|
240
|
+
| `header` | `HeaderFooterOptions` | — | iOS | Header configuration |
|
|
241
|
+
| `footer` | `HeaderFooterOptions` | — | iOS | Footer configuration |
|
|
242
|
+
| `paper` | `PaperOptions` | — | iOS, Android | Paper format |
|
|
243
|
+
| `printer` | `string` | — | iOS | Printer URL for direct printing (skip dialog) |
|
|
244
|
+
| `ui` | `UIOptions` | — | iOS | Printer dialog UI options |
|
|
245
|
+
| `autoFit` | `boolean` | `true` | Android | Auto-scale images to fit content area |
|
|
246
|
+
| `javascript` | `boolean` | `false` | Android | Enable JavaScript in WebView rendering |
|
|
247
|
+
|
|
248
|
+
### PrintOptions
|
|
249
|
+
|
|
250
|
+
Extends `BasePrintOptions` with:
|
|
251
|
+
|
|
252
|
+
| Property | Type | Description |
|
|
253
|
+
|:---------|:-----|:------------|
|
|
254
|
+
| `content` | `string` | Content to print (HTML, text, file URI, or base64 URI) |
|
|
255
|
+
|
|
256
|
+
### PrintHtmlOptions
|
|
257
|
+
|
|
258
|
+
Extends `BasePrintOptions` with:
|
|
259
|
+
|
|
260
|
+
| Property | Type | Description |
|
|
261
|
+
|:---------|:-----|:------------|
|
|
262
|
+
| `html` | `string` **(required)** | HTML string to print |
|
|
263
|
+
|
|
264
|
+
### PrintPdfOptions
|
|
265
|
+
|
|
266
|
+
Extends `BasePrintOptions` with:
|
|
267
|
+
|
|
268
|
+
| Property | Type | Description |
|
|
269
|
+
|:---------|:-----|:------------|
|
|
270
|
+
| `path` | `string` **(required)** | File path or URI to the PDF |
|
|
271
|
+
|
|
272
|
+
### PrintBase64Options
|
|
273
|
+
|
|
274
|
+
Extends `BasePrintOptions` with:
|
|
275
|
+
|
|
276
|
+
| Property | Type | Description |
|
|
277
|
+
|:---------|:-----|:------------|
|
|
278
|
+
| `data` | `string` **(required)** | Base64-encoded data |
|
|
279
|
+
| `mimeType` | `string` **(required)** | MIME type (e.g. `'application/pdf'`, `'image/png'`) |
|
|
280
|
+
|
|
281
|
+
### PrintFileOptions
|
|
282
|
+
|
|
283
|
+
Extends `BasePrintOptions` with:
|
|
284
|
+
|
|
285
|
+
| Property | Type | Description |
|
|
286
|
+
|:---------|:-----|:------------|
|
|
287
|
+
| `path` | `string` **(required)** | File path or URI |
|
|
288
|
+
| `mimeType` | `string` | MIME type (auto-detected if omitted) |
|
|
289
|
+
|
|
290
|
+
### MarginOptions
|
|
291
|
+
|
|
292
|
+
| Property | Type | Description |
|
|
293
|
+
|:---------|:-----|:------------|
|
|
294
|
+
| `top` | `string \| number` | Top margin |
|
|
295
|
+
| `left` | `string \| number` | Left margin |
|
|
296
|
+
| `bottom` | `string \| number` | Bottom margin |
|
|
297
|
+
| `right` | `string \| number` | Right margin |
|
|
298
|
+
|
|
299
|
+
### FontOptions
|
|
300
|
+
|
|
301
|
+
| Property | Type | Description |
|
|
302
|
+
|:---------|:-----|:------------|
|
|
303
|
+
| `name` | `string` | Font family name |
|
|
304
|
+
| `size` | `number` | Font size in points |
|
|
305
|
+
| `color` | `string` | Hex color (e.g. `'#FF0000'`) |
|
|
306
|
+
| `align` | `'left' \| 'right' \| 'center' \| 'justified'` | Text alignment |
|
|
307
|
+
| `bold` | `boolean` | Bold text |
|
|
308
|
+
| `italic` | `boolean` | Italic text |
|
|
309
|
+
|
|
310
|
+
### HeaderFooterOptions
|
|
311
|
+
|
|
312
|
+
| Property | Type | Description |
|
|
313
|
+
|:---------|:-----|:------------|
|
|
314
|
+
| `height` | `string \| number` | Header/footer area height |
|
|
315
|
+
| `text` | `string` | Simple text content |
|
|
316
|
+
| `label` | `LabelOptions` | Single label |
|
|
317
|
+
| `labels` | `LabelOptions[]` | Multiple labels |
|
|
318
|
+
|
|
319
|
+
### LabelOptions
|
|
320
|
+
|
|
321
|
+
| Property | Type | Description |
|
|
322
|
+
|:---------|:-----|:------------|
|
|
323
|
+
| `text` | `string` | Label text. Use `%ld` to insert page number (e.g. `"Page %ld"`) |
|
|
324
|
+
| `showPageIndex` | `boolean` | Display the page number |
|
|
325
|
+
| `font` | `FontOptions` | Label font styling |
|
|
326
|
+
| `top` | `string \| number` | Top offset within the header/footer area |
|
|
327
|
+
| `left` | `string \| number` | Left offset |
|
|
328
|
+
| `right` | `string \| number` | Right offset |
|
|
329
|
+
| `bottom` | `string \| number` | Bottom offset |
|
|
330
|
+
|
|
331
|
+
### PaperOptions
|
|
332
|
+
|
|
333
|
+
| Property | Type | Description |
|
|
334
|
+
|:---------|:-----|:------------|
|
|
335
|
+
| `width` | `string \| number` | Paper width (e.g. `'210mm'`) |
|
|
336
|
+
| `height` | `string \| number` | Paper height (e.g. `'297mm'`) |
|
|
337
|
+
| `name` | `string` | Named paper size (e.g. `'A4'`, `'LETTER'`) |
|
|
338
|
+
| `length` | `string \| number` | Cut length for roll-fed printers (iOS) |
|
|
339
|
+
|
|
340
|
+
**Named paper sizes:** A0–A10, B0–B10, C0–C10, LETTER, LEGAL, TABLOID, LEDGER, JUNIOR_LEGAL, GOVT_LETTER, 4X6, 5X7, 8X10, JIS_B0–JIS_B10, and many more (JPN, ROC, PRC series).
|
|
341
|
+
|
|
342
|
+
### UIOptions
|
|
343
|
+
|
|
344
|
+
| Property | Type | Platform | Description |
|
|
345
|
+
|:---------|:-----|:---------|:------------|
|
|
346
|
+
| `hideNumberOfCopies` | `boolean` | iOS | Hide the copies control |
|
|
347
|
+
| `hidePaperFormat` | `boolean` | iOS | Hide the paper format control |
|
|
348
|
+
| `top` | `number` | iPad | Popover Y position |
|
|
349
|
+
| `left` | `number` | iPad | Popover X position |
|
|
350
|
+
| `width` | `number` | iPad | Popover width |
|
|
351
|
+
| `height` | `number` | iPad | Popover height |
|
|
352
|
+
|
|
353
|
+
### 📏 Unit type
|
|
354
|
+
|
|
355
|
+
Dimension values accept either a number (in points) or a string with a unit suffix:
|
|
356
|
+
|
|
357
|
+
| Suffix | Unit | Example |
|
|
358
|
+
|:-------|:-----|:--------|
|
|
359
|
+
| `pt` | Points | `"72pt"` (= 1 inch) |
|
|
360
|
+
| `in` | Inches | `"2in"` |
|
|
361
|
+
| `mm` | Millimeters | `"210mm"` |
|
|
362
|
+
| `cm` | Centimeters | `"29.7cm"` |
|
|
363
|
+
|
|
364
|
+
A plain number is interpreted as points: `72` is the same as `"72pt"` (1 inch).
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 📤 Return Types
|
|
369
|
+
|
|
370
|
+
### PrintResult
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
interface PrintResult {
|
|
374
|
+
success: boolean;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### CanPrintResult
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
interface CanPrintResult {
|
|
382
|
+
available: boolean;
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### PrintableTypesResult
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
interface PrintableTypesResult {
|
|
390
|
+
types: string[];
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### PickResult
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
interface PickResult {
|
|
398
|
+
url?: string; // Printer URL, or undefined if cancelled
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 🔗 URI Schemes
|
|
405
|
+
|
|
406
|
+
| Scheme | Example | Description |
|
|
407
|
+
|:-------|:--------|:------------|
|
|
408
|
+
| `file:///` | `file:///path/to/file.pdf` | Absolute file path |
|
|
409
|
+
| `file://` | `file://assets/image.png` | App assets/bundle |
|
|
410
|
+
| `res:` | `res://icon` | App resources |
|
|
411
|
+
| `base64:` | `base64://JVBERi0...` | Base64-encoded data |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## 🖨️ Direct Print (iOS)
|
|
416
|
+
|
|
417
|
+
On iOS, you can send content directly to a printer without showing the print dialog by passing the printer URL:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
await Printer.printHtml({
|
|
421
|
+
html: '<p>Direct print</p>',
|
|
422
|
+
printer: 'ipp://printer.local.:631/ipp/print',
|
|
423
|
+
});
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Use [`pick()`](#-pick) to let the user select a printer and retrieve its URL:
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
const { url } = await Printer.pick();
|
|
430
|
+
if (url) {
|
|
431
|
+
await Printer.printHtml({ html: content, printer: url });
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## 💡 Full Example
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import { Printer } from '@dimer47/capacitor-plugin-printer';
|
|
441
|
+
|
|
442
|
+
await Printer.printHtml({
|
|
443
|
+
html: `
|
|
444
|
+
<h1>Invoice #1234</h1>
|
|
445
|
+
<p>Date: 2025-01-15</p>
|
|
446
|
+
<table>
|
|
447
|
+
<tr><td>Item</td><td>$42.00</td></tr>
|
|
448
|
+
</table>
|
|
449
|
+
`,
|
|
450
|
+
name: 'Invoice-1234',
|
|
451
|
+
orientation: 'portrait',
|
|
452
|
+
monochrome: false,
|
|
453
|
+
duplex: 'long',
|
|
454
|
+
paper: { name: 'A4' },
|
|
455
|
+
margin: { top: '1cm', left: '1cm', right: '1cm', bottom: '1cm' },
|
|
456
|
+
header: {
|
|
457
|
+
height: '2cm',
|
|
458
|
+
label: {
|
|
459
|
+
text: 'My Company',
|
|
460
|
+
font: { bold: true, size: 14, align: 'center' },
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
footer: {
|
|
464
|
+
height: '1.5cm',
|
|
465
|
+
label: {
|
|
466
|
+
text: 'Page %ld',
|
|
467
|
+
showPageIndex: true,
|
|
468
|
+
font: { size: 10, align: 'center' },
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## 📊 Platform Feature Matrix
|
|
477
|
+
|
|
478
|
+
| Feature | iOS | Android | Web |
|
|
479
|
+
|:--------|:---:|:-------:|:---:|
|
|
480
|
+
| Print HTML | ✅ | ✅ | ✅ |
|
|
481
|
+
| Print plain text | ✅ | ✅ | ✅ |
|
|
482
|
+
| Print PDF | ✅ | ✅ | — |
|
|
483
|
+
| Print images | ✅ | ✅ | — |
|
|
484
|
+
| Print base64 data | ✅ | ✅ | — |
|
|
485
|
+
| Print WebView | ✅ | ✅ | ✅ |
|
|
486
|
+
| Headers & footers | ✅ | — | — |
|
|
487
|
+
| Direct print (printer URL) | ✅ | — | — |
|
|
488
|
+
| Printer picker (`pick`) | ✅ | — | — |
|
|
489
|
+
| Number of copies | ✅ | — | — |
|
|
490
|
+
| Paper size selection | ✅ | ✅ | — |
|
|
491
|
+
| JavaScript in WebView | — | ✅ | — |
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## 🤝 Contributing
|
|
496
|
+
|
|
497
|
+
1. Fork it
|
|
498
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
499
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
500
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
501
|
+
5. Create a new Pull Request
|
|
502
|
+
|
|
503
|
+
## 🧾 License
|
|
504
|
+
|
|
505
|
+
This software is released under the [Apache 2.0 License](http://opensource.org/licenses/Apache-2.0).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
2
|
+
|
|
3
|
+
ext {
|
|
4
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
5
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
6
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
|
|
7
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
buildscript {
|
|
11
|
+
repositories {
|
|
12
|
+
google()
|
|
13
|
+
mavenCentral()
|
|
14
|
+
}
|
|
15
|
+
dependencies {
|
|
16
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
17
|
+
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply plugin: 'com.android.library'
|
|
22
|
+
apply plugin: 'kotlin-android'
|
|
23
|
+
|
|
24
|
+
android {
|
|
25
|
+
namespace = "com.nichedev.capacitor.printer"
|
|
26
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
27
|
+
defaultConfig {
|
|
28
|
+
minSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
|
29
|
+
targetSdkVersion = project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
30
|
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
31
|
+
}
|
|
32
|
+
buildTypes {
|
|
33
|
+
release {
|
|
34
|
+
minifyEnabled = false
|
|
35
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
compileOptions {
|
|
39
|
+
sourceCompatibility = JavaVersion.VERSION_21
|
|
40
|
+
targetCompatibility = JavaVersion.VERSION_21
|
|
41
|
+
}
|
|
42
|
+
sourceSets {
|
|
43
|
+
main.java.srcDirs += 'src/main/kotlin'
|
|
44
|
+
test.java.srcDirs += 'src/test/kotlin'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
kotlin {
|
|
49
|
+
compilerOptions {
|
|
50
|
+
jvmTarget = JvmTarget.JVM_21
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
repositories {
|
|
55
|
+
google()
|
|
56
|
+
mavenCentral()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
dependencies {
|
|
60
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
61
|
+
implementation project(':capacitor-android')
|
|
62
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
63
|
+
implementation "androidx.print:print:1.1.0"
|
|
64
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.20"
|
|
65
|
+
testImplementation "junit:junit:$junitVersion"
|
|
66
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
67
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
68
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
package com.nichedev.capacitor.printer
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.os.CancellationSignal
|
|
5
|
+
import android.os.ParcelFileDescriptor
|
|
6
|
+
import android.print.PageRange
|
|
7
|
+
import android.print.PrintAttributes
|
|
8
|
+
import android.print.PrintDocumentAdapter
|
|
9
|
+
import android.print.PrintDocumentInfo
|
|
10
|
+
import java.io.FileOutputStream
|
|
11
|
+
import java.io.IOException
|
|
12
|
+
import java.io.InputStream
|
|
13
|
+
|
|
14
|
+
class PrintAdapter(
|
|
15
|
+
private val jobName: String,
|
|
16
|
+
private val pageCount: Int,
|
|
17
|
+
private val input: InputStream,
|
|
18
|
+
private val callback: () -> Unit
|
|
19
|
+
) : PrintDocumentAdapter() {
|
|
20
|
+
|
|
21
|
+
override fun onLayout(
|
|
22
|
+
oldAttributes: PrintAttributes?,
|
|
23
|
+
newAttributes: PrintAttributes,
|
|
24
|
+
cancellationSignal: CancellationSignal?,
|
|
25
|
+
callback: LayoutResultCallback,
|
|
26
|
+
extras: Bundle?
|
|
27
|
+
) {
|
|
28
|
+
if (cancellationSignal?.isCanceled == true) {
|
|
29
|
+
callback.onLayoutCancelled()
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
val pdi = PrintDocumentInfo.Builder(jobName)
|
|
34
|
+
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
|
|
35
|
+
.setPageCount(pageCount)
|
|
36
|
+
.build()
|
|
37
|
+
|
|
38
|
+
val changed = newAttributes != oldAttributes
|
|
39
|
+
callback.onLayoutFinished(pdi, changed)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun onWrite(
|
|
43
|
+
pages: Array<out PageRange>,
|
|
44
|
+
destination: ParcelFileDescriptor,
|
|
45
|
+
cancellationSignal: CancellationSignal?,
|
|
46
|
+
callback: WriteResultCallback
|
|
47
|
+
) {
|
|
48
|
+
if (cancellationSignal?.isCanceled == true) {
|
|
49
|
+
callback.onWriteCancelled()
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
val output = FileOutputStream(destination.fileDescriptor)
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
PrintIO.copy(input, output)
|
|
57
|
+
} catch (e: IOException) {
|
|
58
|
+
callback.onWriteFailed(e.message)
|
|
59
|
+
return
|
|
60
|
+
} finally {
|
|
61
|
+
PrintIO.close(output)
|
|
62
|
+
try { destination.close() } catch (_: IOException) { }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
callback.onWriteFinished(arrayOf(PageRange.ALL_PAGES))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override fun onFinish() {
|
|
69
|
+
super.onFinish()
|
|
70
|
+
PrintIO.close(input)
|
|
71
|
+
callback()
|
|
72
|
+
}
|
|
73
|
+
}
|