@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.
Files changed (36) hide show
  1. package/CapacitorPluginPrinter.podspec +17 -0
  2. package/LICENSE +202 -0
  3. package/Package.swift +31 -0
  4. package/README.md +505 -0
  5. package/android/build.gradle +68 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintAdapter.kt +73 -0
  8. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintContent.kt +78 -0
  9. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintIO.kt +136 -0
  10. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintManager.kt +219 -0
  11. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintOptions.kt +260 -0
  12. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrintProxy.kt +44 -0
  13. package/android/src/main/kotlin/com/nichedev/capacitor/printer/PrinterPlugin.kt +267 -0
  14. package/dist/esm/definitions.d.ts +307 -0
  15. package/dist/esm/definitions.js +2 -0
  16. package/dist/esm/definitions.js.map +1 -0
  17. package/dist/esm/index.d.ts +4 -0
  18. package/dist/esm/index.js +7 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/web.d.ts +13 -0
  21. package/dist/esm/web.js +47 -0
  22. package/dist/esm/web.js.map +1 -0
  23. package/dist/plugin.cjs.js +61 -0
  24. package/dist/plugin.cjs.js.map +1 -0
  25. package/dist/plugin.js +64 -0
  26. package/dist/plugin.js.map +1 -0
  27. package/ios/Sources/PrinterPlugin/PrinterControllerHelper.swift +33 -0
  28. package/ios/Sources/PrinterPlugin/PrinterFont.swift +99 -0
  29. package/ios/Sources/PrinterPlugin/PrinterInfo.swift +64 -0
  30. package/ios/Sources/PrinterPlugin/PrinterItem.swift +104 -0
  31. package/ios/Sources/PrinterPlugin/PrinterLayout.swift +61 -0
  32. package/ios/Sources/PrinterPlugin/PrinterPaper.swift +71 -0
  33. package/ios/Sources/PrinterPlugin/PrinterPlugin.swift +327 -0
  34. package/ios/Sources/PrinterPlugin/PrinterRenderer.swift +135 -0
  35. package/ios/Sources/PrinterPlugin/PrinterUnit.swift +45 -0
  36. package/package.json +75 -0
package/README.md ADDED
@@ -0,0 +1,505 @@
1
+ # 🖨️ Capacitor Plugin Printer
2
+
3
+ ![Version](https://img.shields.io/npm/v/@dimer47/capacitor-plugin-printer?color=red&style=flat-square) ![Last update](https://img.shields.io/github/last-commit/dimer47/capacitor-plugin-printer?color=yellow&label=Last%20update&style=flat-square) ![Bundle size](https://img.shields.io/bundlephobia/minzip/@dimer47/capacitor-plugin-printer?color=green&label=bundle%20size&style=flat-square) ![Repo size](https://img.shields.io/github/repo-size/dimer47/capacitor-plugin-printer?style=flat-square) ![Downloads](https://img.shields.io/npm/dt/@dimer47/capacitor-plugin-printer?style=flat-square) ![License](https://img.shields.io/github/license/dimer47/capacitor-plugin-printer?style=flat-square) ![Capacitor](https://img.shields.io/badge/Capacitor-8-blue?style=flat-square&logo=capacitor) ![iOS](https://img.shields.io/badge/iOS-15%2B-black?style=flat-square&logo=apple) ![Android](https://img.shields.io/badge/Android-7.0%2B-green?style=flat-square&logo=android)
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,3 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+ </manifest>
@@ -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
+ }