nitro_printing 0.0.6
nitro_printing: ^0.0.6 copied to clipboard
A high-performance Flutter printing plugin built on Nitro for Flutter. Supports text, image, PDF, raw/ESC-POS/ZPL printing, print-job management, mDNS printer discovery, IPP status queries, and a buil [...]
nitro_printing #
Live demo (web) โ the example app running on WASM.
A Flutter printing plugin built on the Nitrogen SDK (a Flutter port of React Native Nitro Modules): native calls go through Dart FFI instead of method channels. Docs: https://nitro.shreeman.dev โ demo: https://printing.shreeman.dev
Features #
- Synchronous printer queries (
getPrintersCount(),isPrintingSupported()) - Text, image, PDF, and file printing with a full
PrintSettingsmodel - Raw TCP, ESC/POS, and ZPL printing
- mDNS/Bonjour printer discovery and IPP status queries
- Print job management with
onPrintJobChanged/onPrinterStatusChangedstreams - Print preview, print-to-file, batch printing
- Built-in Material 3 settings page (
NitroPrintSettingsPage) - Android, iOS, macOS, Windows, Linux, and Web (WASM)
Installation #
dependencies:
flutter:
sdk: flutter
nitro_printing: ^0.0.5
flutter pub get
Required Platform Setup #
Before running your application, ensure you have configured the required permissions and system packages for your target platforms:
๐ค Android #
The plugin requires the INTERNET permission to connect to network printers (IPP, TCP raw sockets) and to run mDNS discovery.
In your app's android/app/src/main/AndroidManifest.xml, ensure the following is present:
<uses-permission android:name="android.permission.INTERNET"/>
(Note: The plugin's own manifest includes this permission, so Gradle will merge it automatically, but it is recommended to declare it in the main app.)
๐ iOS #
The plugin uses Apple's Bonjour/mDNS framework (NetServiceBrowser) to search for network-enabled IPP printers. On iOS 14+, you must declare local network permissions and the specific Bonjour services the app will query in ios/Runner/Info.plist:
- Local Network Usage Description: A description explaining why local network access is needed.
- Bonjour Services: The list of service types (
_ipp._tcpand_ipps._tcp).
Add the following keys to your Info.plist:
<key>NSLocalNetworkUsageDescription</key>
<string>This app requires access to the local network to discover and connect to network printers.</string>
<key>NSBonjourServices</key>
<array>
<string>_ipp._tcp</string>
<string>_ipps._tcp</string>
</array>
๐ป macOS #
1. Sandbox Entitlements
If your macOS app has App Sandbox enabled (default for Flutter templates), you must add the printing and network client entitlements in both macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:
<!-- Allow printing operations -->
<key>com.apple.security.print</key>
<true/>
<!-- Allow outgoing network connections to TCP/IPP/mDNS printers -->
<key>com.apple.security.network.client</key>
<true/>
2. Local Network & Bonjour (macOS 11+)
If sandbox is enabled and you are performing printer discovery, declare the Bonjour service details in macos/Runner/Info.plist (similar to iOS):
<key>NSLocalNetworkUsageDescription</key>
<string>This app requires access to the local network to discover and connect to network printers.</string>
<key>NSBonjourServices</key>
<array>
<string>_ipp._tcp</string>
<string>_ipps._tcp</string>
</array>
๐ง Linux #
1. Compilation Dependencies
The Linux native implementation links against CUPS (Common UNIX Printing System). You must install the CUPS development headers and pkg-config on your build machine to compile the application:
- Ubuntu/Debian:
sudo apt-get install -y libcups2-dev pkg-config - Fedora/RHEL:
sudo dnf install cups-devel pkgconfig - Arch Linux:
sudo pacman -S cups pkgconf
2. Runtime Requirements
A running CUPS daemon (cupsd) is required on the target machine for local printer queries and job spooling. This is pre-installed and running on standard desktop Linux distributions, but may need to be installed manually on minimal or headless systems.
๐ช Windows #
No special permissions, configuration, or external dependencies are required. The plugin uses standard Win32 print spooler APIs (like WinSpool) which are built into all Windows environments.
๐ Web (WASM) #
The web backend is the same C++ module compiled to WebAssembly (bundled automatically as a Flutter asset โ no setup beyond one call). Module instantiation is asynchronous on web, so await the ready hook before first use; it is a no-op on every native platform:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ensureNitroPrintingReady(); // instantiates the WASM module on web
runApp(const App());
}
WebUSB and the browser print dialog require a secure context (HTTPS or
localhost). See Web Support for what each API does on web and
which PrintSettings fields are respected there.
Quick Start #
import 'package:nitro_printing/nitro_printing.dart';
// Once at startup: instantiates the WASM module on web, no-op on native.
await ensureNitroPrintingReady();
final printing = NitroPrinting.instance;
// Synchronous โ no await, no Isolate
if (!printing.isPrintingSupported()) return;
// Print a PDF
final pdfBytes = await loadPdfAsset();
final result = await printing.printPdf(
pdfBytes,
settings: PrintSettings(
printerId: 'My Printer',
paperSize: PaperSize.a4,
quality: PrintQuality.high,
duplex: true,
),
);
if (result.success) {
print('Job ID: ${result.jobId}');
}
API Reference #
NitroPrinting.instance #
The singleton entry point. Defined as a @NitroModule extending HybridObject โ
the Nitrogen runtime creates the FFI bridge automatically via code generation.
Synchronous Queries (no await, no Isolate overhead) #
These are direct Dart FFI calls that execute in < 1 ยตs โ safe to call on the UI thread.
bool isPrintingSupported();
int getPrintersCount();
String getPrinterDriverVersion(String printerId);
Printer Info & Discovery (@nitroAsync) #
Future<List<PrinterInfo>> getAllPrinters();
Future<NitroResultValue<PrinterInfo>> getPrinterAt(int index);
Future<NitroResultValue<PrinterInfo>> getDefaultPrinter();
Future<NitroResultValue<PrinterCapabilities>> getPrinterCapabilities(String printerId);
Example โ populate a printer list:
final printers = await printing.getAllPrinters();
Print Operations (@nitroAsync) #
Marked @nitroAsync โ dispatched on a background isolate, returns to the main isolate.
Future<PrintResult> printText(String text, {PrintSettings? settings});
Future<PrintResult> printImage(Uint8List imageData, {PrintSettings? settings});
Future<PrintResult> printPdf(Uint8List pdfData, {PrintSettings? settings});
Future<PrintResult> printDocument(PrintDocument document, {PrintSettings? settings});
Future<bool> printFile(String filePath, {PrintSettings? settings});
Future<List<PrintResult>> printBatch(List<PrintDocument> documents, bool stopOnError, {PrintSettings? settings});
OS Print Dialog (@nitroAsync) #
Show the native OS print dialog, or use the controller for advanced flows:
Future<PrintDialogResult> showPrintDialog(PrintDocument document, {PrintSettings? initialSettings});
// Controller for orchestration:
final controller = PrintDialogController(initialSettings: PrintSettings(copies: 2));
final result = await controller.showDialog(document);
if (result.confirmed) {
// result.confirmedSettings reflects user choices
await controller.printDirect(document);
}
PrintResult contains success, jobId, errorMessage, errorCode.
Export / Virtual Print #
/// Render a document to PDF bytes without sending to a printer (for previews).
Future<PreviewResult> renderPreview(PrintDocument document, {PrintSettings? settings});
/// Count how many pages a document will produce.
Future<int> getPageCount(PrintDocument document);
/// Write a rendered PDF to disk (virtual / file print).
Future<bool> printToFile(PrintDocument document, String outputPath, {PrintSettings? settings});
Raw Protocol Printing #
Direct TCP socket output โ no OS print dialog, no driver needed.
/// Send raw bytes to a printer on port 9100 or via IPP.
Future<PrintResult> printRaw(Uint8List data, {PrintSettings? settings});
/// ESC/POS thermal receipt printers (socket://host:port).
Future<PrintResult> printEscPos(Uint8List escPosData, {PrintSettings? settings});
/// ZPL label printers (Zebra, socket://host:9100).
Future<PrintResult> printZpl(String zpl, {PrintSettings? settings});
/// Cancel any in-progress raw/ESC-POS/ZPL network job.
Future<bool> cancelRawPrint();
Set PrintSettings.printerId to an IP address or URI (socket://192.168.1.5:9100, ipp://...).
Print Job Management #
Future<bool> cancelPrintJob(String jobId);
Future<bool> pausePrintJob(String jobId);
Future<bool> resumePrintJob(String jobId);
Future<bool> clearPrintQueue();
Future<int> getPrintJobsCount();
Future<NitroResultValue<PrintJob>> getPrintJobAt(int index);
Future<NitroResultValue<PrintJob>> getPrintJobStatus(String jobId);
Printer Discovery (mDNS/Bonjour) #
Future<bool> startPrinterDiscovery();
Future<bool> stopPrinterDiscovery();
// @NitroStream โ zero-copy reactive stream of discovered IPP printers
Stream<DiscoveredPrinter> onPrinterDiscovered();
Example:
final sub = printing.onPrinterDiscovered().listen((p) {
print('Found: ${p.name} at ${p.uri}');
});
await printing.startPrinterDiscovery();
// ... later:
await printing.stopPrinterDiscovery();
await sub.cancel();
Connection & Administration #
/// TCP probe โ check if a printer is reachable.
Future<bool> testPrinterConnection(String printerId, {int? timeoutSeconds});
/// Set the system-default printer (macOS / Windows only).
Future<bool> setDefaultPrinter(String printerId);
Platform UX #
/// Open the OS print queue window for a printer (empty string = all printers).
Future<bool> openSystemPrintQueue(String printerId);
/// Open OS printer-properties dialog (macOS / Windows only).
Future<bool> openPrinterProperties(String printerId);
Detailed IPP Status #
/// Query live printer status via IPP Get-Printer-Attributes.
Future<NitroResultValue<PrinterStatusDetail>> getPrinterStatusDetail(
String printerId, {
int? timeoutSeconds,
});
PrinterStatusDetail exposes: isOnline, isReady, hasPaperJam, isOutOfPaper,
isOutOfInk, per-channel ink levels (inkLevelBlack/Cyan/Magenta/Yellow), tonerLevel,
paperLevel, jobsInQueue, printerState, stateReasons, and more.
Real-Time Streams (@NitroStream) #
All streams are annotated with @NitroStream(backpressure: Backpressure.dropLatest) โ
the Nitrogen runtime uses Dart_PostCObject to push events from the native thread directly
to Dart with no method-channel round-trip.
Stream<PrintJobUpdate> onPrintJobChanged(); // job state + progress
Stream<PrinterStatus> onPrinterStatusChanged(); // online/offline, ink, queue depth
Stream<DiscoveredPrinter> onPrinterDiscovered(); // mDNS discovery events
Batch Printing (Dart-side orchestration) #
final results = await printing.printBatch(
[doc1, doc2, doc3],
stopOnError: true,
settings: PrintSettings(copies: 2),
);
Built-in Print Settings UI #
A Material 3 full-screen settings editor โ no extra dependency needed.
final settings = await NitroPrintSettingsPage.show(context);
if (settings != null) {
await printing.printPdf(pdfBytes, settings: settings);
}
The page exposes: printer picker, show-dialog toggle, job name, paper size (including custom pt dimensions), orientation, copies stepper, pages-per-sheet, page range, fit-to-page, quality, media type, color/duplex/collate toggles, header/footer text, and input tray.
Data Models #
PrintSettings #
| Field | Type | Default | Description |
|---|---|---|---|
printerId |
String |
'' |
Printer ID / IP / URI |
paperSize |
PaperSize |
.a4 |
a4, a5, letter, legal, custom |
orientationDegrees |
double |
0.0 |
0=portrait, 90=landscape, 180/270=reverse |
quality |
PrintQuality |
.normal |
draft, normal, high, best |
copies |
int |
1 |
Number of copies |
collate |
bool |
false |
Collate multi-copy jobs |
duplex |
bool |
false |
Double-sided |
color |
bool |
true |
Color vs grayscale |
marginTop/Bottom/Left/Right |
double |
0 |
Margins in PostScript points |
jobName |
String |
'' |
Spooler job name |
pagesPerSheet |
int |
1 |
1, 2, 4, 6, 8, 16 |
showPrintDialog |
bool |
true |
false = silent direct print |
pageRangeFrom/To |
int |
0 |
1-based; 0 = start/end |
customPaperWidth/Height |
double |
0 |
Points, when paperSize == .custom |
fitToPage |
bool |
false |
Scale to printable area |
mediaType |
MediaType |
.plain |
plain, glossy, matte, photo, label, envelope |
headerText / footerText |
String |
'' |
Per-page header/footer |
inputTray |
String |
'' |
Tray name, e.g. "Tray 1" |
networkTimeoutSeconds |
int |
30 |
TCP/IPP timeout |
Other Models #
| Model | Key Fields |
|---|---|
PrinterInfo |
id, name, address, isDefault, isAvailable |
PrinterCapabilities |
color, duplex, copy count, paper sizes, quality levels, max DPI, borderless, input trays |
PrintJob |
id, printerId, documentTitle, state (PrintState), progress (0โ100), createdAt, completedAt, errorMessage, pagesPrinted |
PrintDocument |
id, title, type (DocumentType: plainText/html/pdf/image), data (Uint8List) |
DiscoveredPrinter |
id, name, host, port, serviceType (e.g. _ipp._tcp), uri, isAvailable |
PrinterStatusDetail |
isOnline, isReady, hasPaperJam, isOutOfPaper, ink levels per channel, tonerLevel, paperLevel, stateReasons |
Platform Support #
| Platform | Discovery | Raw/ESC-POS/ZPL | System Dialog | |
|---|---|---|---|---|
| Android | โ | โ | โ | โ (Print Services) |
| iOS | โ | โ | โ | โ (AirPrint) |
| macOS | โ | โ | โ | โ |
| Windows | โ | โ | โ | โ |
| Linux | โ | โ | โ | โ (CUPS) |
| Web | โ (browser dialog / Web Printing) | โ ๏ธ WebUSB picker | โ (WebUSB / ws relay / TCPSocket) | โ (browser dialog) |
Web Support #
The web backend is the same C++ implementation compiled to WASM. Capabilities are feature-detected at runtime; unsupported operations fail with a typed error instead of hanging.
Supported on web #
| Feature | Notes |
|---|---|
| Document printing (text / HTML / image / PDF) | Browser print dialog, with PrintSettings applied to the document: paper size, orientation, margins, copies (collated/uncollated), grayscale, header/footer, page ranges, N-up, job name |
| Silent printing to any OS printer | Via the first-party Nitro Print Agent (agent:) or QZ Tray (qz:) โ spool-confirmed results, native job ids |
| Silent PDF system jobs | Web Printing API in Isolated Web Apps (Chrome 147+), with IPP attributes and page-progress tracking |
| Raw / ESC-POS / ZPL | WebUSB, Web Serial, Web Bluetooth, ws:// relay, Direct Sockets TCP (IWA), or either local agent. ESC/POS text is CP437-translated; images raster to GS v 0 |
| Printer enumeration & status | Granted USB/serial/BLE devices, agent printers, and (IWA) the full system list with IPP capabilities and state reasons; live status streams from Web Printing, QZ, and the agent |
| Discovery | USB/serial/BLE device pickers, local-agent probing, and (IWA) one-shot mDNS |
| Preview & export | Page-accurate live preview (copies/N-up/grayscale/decor visible), PDF page counts and page-range extraction, HTMLโPDF rasterization, printToFile download, printFile for http(s)/data:/blob: URLs |
| Job tracking & typed status | Every print tracked with onPrintJobChanged; PrintErrorCode, PrintOutcome, PrintJob.failureReason, lastPrintJob(), resumePrintJob for raw jobs |
| Page decoration | WebPrintDecor โ per-page watermark/letterhead, HTML header/footer |
| Both web compilers | dart2js and dart2wasm (--wasm) |
Web limitations #
| Limitation | Detail / workaround |
|---|---|
| Print-vs-Cancel in the browser dialog is unknowable | No web API reveals it. Dialog prints report PrintOutcome.dialogShown; use dialogDurationMs/dialogGuess heuristics, PrintOutcomeConfirmation.markJobOutcome (ask the user), or a verified path (agent / raw / Web Printing) |
| No default-printer concept | getDefaultPrinter/setDefaultPrinter return NitroErr/false everywhere on web |
| No pause/resume of OS jobs, driver version, or OS print-queue/properties UI | No web API in any context |
| Dialog flow cannot force duplex, quality, or media type | The browser dialog owns those; all three work on Web Printing jobs, duplex/quality also via the agents |
| PDF documents print as-is in the dialog flow | Settings apply via qz:/agent:/Web Printing instead; pageRange extraction covers classic-xref PDFs only (others print in full) |
| No system-printer enumeration on the open web | Requires an Isolated Web App or a local agent |
| Device transports are Chromium-only and need a user-gesture grant | WebUSB/Web Serial/Web Bluetooth; Windows WebUSB may additionally need a WinUSB driver (Zadig) for printers claimed by usbprint.sys |
| Direct raw TCP only in Isolated Web Apps | On the open web use a ws:// relay or a local agent |
| HTML rendering is raster-based, inline content only | External images/fonts don't load in the SVG sandbox; HTML previews are JPEG pages, not vector PDF |
| ESC/POS text is CP437 only; batch item status caps at 64 documents | Unmappable glyphs print as ?; items past 64 report failed |
| Secure context required | HTTPS or localhost; local endpoints (relay/agents) are gated by Chrome's Local Network Access permission |
How each API behaves on web #
| API | Open web (any HTTPS Chromium page) | Isolated Web App (Chrome 147+) |
|---|---|---|
printText / printImage / printDocument |
Browser print dialog (hidden-iframe flow). Plain text with a raw printerId (usb:/ws:///socket://) is ESC/POS-encoded (init + text + feed/cut) and sent straight to the thermal printer |
same |
printPdf |
Browser print dialog; a qz: or system printerId prints silently |
Web Printing API job with state tracking |
printBatch |
Sequential dialog prints, per-item results | same |
showPrintDialog |
Browser dialog; confirmed = dialog shown & closed (browsers cannot reveal Print-vs-Cancel) |
same |
printRaw / printEscPos / printZpl |
WebUSB (usb:), Web Serial (serial:[baud]), Web Bluetooth (ble:[name]), QZ Tray agent (qz:, spool-confirmed), or ws:// relay (websockify). ESC/POS text is CP437-translated; images raster to GS v 0 |
also direct TCPSocket to port 9100, no relay |
getAllPrinters / getPrinterAt / getPrintersCount |
Granted WebUSB devices | + full system printer list (Web Printing) |
getPrinterCapabilities / getPrinterStatusDetail |
Basic WebUSB info | Full IPP attributes (media, duplex, color, quality, state reasons) |
startPrinterDiscovery |
Opens the WebUSB, Web Serial, then Web Bluetooth device pickers (needs a user gesture) and probes the QZ agent; grants emit onPrinterDiscovered |
+ one-shot mDNS query over Direct Sockets UDP (_ipp/_pdl-datastream/_printer) |
testPrinterConnection |
USB open-probe or ws:// reachability |
+ TCP connect probe |
getPrintJobsCount / getPrintJobAt / getPrintJobStatus |
Every web print is tracked (dialog, raw transports, batch items) with onPrintJobChanged events and lastPrintJob() |
+ Web Printing system jobs with page progress |
cancelPrintJob / clearPrintQueue |
Unknown ids are inert | Cancels/clears Web Printing jobs |
resumePrintJob |
Retries a finished raw-transport job's kept payload; dialog/Web Printing jobs are not resumable | same |
| Job failure reasons | PrintJob.failureReason โ typed (mediaEmpty, mediaJam, tonerEmpty, coverOpen, printerOffline, โฆ) parsed from the job's error |
populated from IPP printer-state-reasons |
| Typed errors | PrintResult.errorKind โ PrintErrorCode enum (noUsbDevice, relayTimeout, tcpUnavailable, โฆ) for switch-based handling |
same |
| Outcomes | PrintResult.outcome / PrintJob.outcome โ PrintOutcome: printed only when delivery was verified (raw transports, system jobs); dialog prints report dialogShown since no web API reveals Print-vs-Cancel |
Web Printing jobs report IPP terminal states incl. cancelled |
| Dialog-outcome signals | PrintResult.dialogDurationMs (measured via afterprint), the dialogGuess heuristic, and PrintOutcomeConfirmation.markJobOutcome(jobId, printed:) to settle a job after asking the user |
not needed (real job states) |
| Page decoration | WebPrintDecor.configure(backgroundHtml:, headerHtml:, footerHtml:) โ per-page watermark/letterhead and HTML header/footer |
same |
renderPreview |
PDF documents pass through (pageRange extracts a sub-document in wasm); plain text renders to a generated PDF sized by PrintSettings; images become a one-page PDF; HTML rasterizes to a multi-page PDF (inline content only) |
same |
getPageCount |
PDF page-tree walk; text paginated at 60 lines/page; HTML rasterized and counted | same |
printToFile |
Browser download โ text, images, and HTML render to a real PDF first | same |
printFile |
http(s)://, data:, blob: URLs are fetched and printed by sniffed type; filesystem paths return false |
same |
getDefaultPrinter / setDefaultPrinter |
NitroErr / false โ no default-printer concept on the web |
same |
pausePrintJob |
false โ no web API | same |
getPrinterDriverVersion / openSystemPrintQueue / openPrinterProperties |
Empty / false โ OS surface unreachable from the sandbox | same |
The sync @NitroResult lookups (getPrinterAt, capabilities, status detail,
jobs) are served from the cache the last getAllPrinters() populated โ call
it first, or they fail with a NitroErr that says exactly that.
printerId routing on web #
Raw printing and PDF job submission pick their transport from the
PrintSettings.printerId scheme:
printerId |
Transport |
|---|---|
(empty) or usb:VID:PID[:serial] |
WebUSB bulk transfer to the (matching) granted USB printer |
ws://host:port / wss://host:port |
WebSocketโTCP relay (e.g. websockify forwarding to the printer's port 9100) |
socket://host:port or a bare IP |
Direct Sockets TCPSocket (Isolated Web Apps only); elsewhere fails with guidance |
agent: or agent:<printer id> |
First-party Nitro Print Agent: silent text/image/PDF/raw to any OS printer through this plugin's own native backends, native job ids and status |
qz: or qz:Printer Name |
QZ Tray local agent: silent raw and PDF printing to any OS printer, spool-confirmed results, and OS printer status on onPrinterStatusChanged. QZ shows its own Allow prompt; WebPrintAgent.configure(endpoint:) overrides the default ports |
A system printer name from getAllPrinters() |
Web Printing API PDF job (Isolated Web Apps only) |
Which PrintSettings fields are respected on web #
Dialog flows apply settings to the document itself (CSS @page, content
repetition, grayscale), so they take effect even though the browser dialog can
override them. PDF documents print as-is in the dialog flow; use a qz: or
Web Printing printer for attribute control over PDFs.
| Field | Dialog printing (text / HTML / image) | Raw (WebUSB / relay / TCP) | Web Printing PDF job |
|---|---|---|---|
printerId |
picks the flow: a Web Printing printer name routes to a silent job; otherwise the user picks the target in the dialog | โ selects the transport & device | โ selects the printer |
copies |
โ page content is repeated per copy inside one job | โ
repeats the payload (printZpl always sends once โ ZPL carries its own quantity commands) |
โ
copies attribute |
paperSize / customPaperWidth/Height |
โ
CSS @page size (A4/A5/letter/legal/custom pt) |
n/a | โ
media size name (custom โ printer default) |
orientationDegrees |
โ
portrait/landscape via @page size |
n/a | โ
orientation-requested |
margins (marginTop/Right/Bottom/Left, pt) |
โ
CSS @page margin |
n/a | โ |
color |
โ
false renders grayscale |
n/a | โ
print-color-mode |
duplex |
dialog-controlled by the user | n/a | โ
sides (two-sided-long-edge) |
quality |
dialog-controlled by the user | n/a | โ
print-quality (draft/normal/high) |
headerText / footerText |
โ per page (all document types) | n/a | โ |
pageRangeFrom/To |
โ plain-text documents (hard-paginated at 60 lines/page) | n/a | โ
page-ranges |
fitToPage |
โ images scale to page width | n/a | โ |
pagesPerSheet |
โ N-up grid layout (2/4/6/8/16 per sheet) | n/a | โ |
jobName |
โ document title โ names the print job and the default save-as-PDF file | โ | โ job title |
networkTimeoutSeconds |
โ | โ bounds relay/TCP connect + send | โ |
collate |
n/a (single document) | n/a | โ
multiple-document-handling |
mediaType |
not mappable | n/a | โ
media-type (glossy/matte/photo/labels/envelope) |
showPrintDialog |
effectively always true โ the dialog is the only document path unless printerId names a Web Printing printer |
n/a | n/a |
showPrintDialog()'s confirmedSettings echoes the initialSettings you
passed (or defaults) โ the browser cannot report what the user actually chose
in its dialog.
Nitro Print Agent (the agent: transport โ any OS printer) #
agent/ in this repo is a small first-party desktop app that wraps this
plugin's own native backends behind ws://127.0.0.1:9629. A web app using an
agent: printerId gets silent printing to any OS printer with real native
PrintResults (spool-confirmed PrintOutcome.printed, native job ids) and
live printer/job status โ no third-party agent.
- Build and run it:
cd agent && flutter run -d macos(orwindows/linux; distribute the built app to workstations). - Print with
PrintSettings(printerId: 'agent:')(default printer) or'agent:<printer id>'. Text, image, and PDF go through the native driver; raw/ESC-POS/ZPL pass through unchanged. startPrinterDiscovery()probes the agent and emits its printers;getPrinterStatusDetail('agent:โฆ')returns live native status.- Non-standard port:
WebPrintAgent.configure(agentEndpoint: 'ws://host:port')(agent side:--portorNITRO_PRINT_AGENT_PORT).
The agent binds to loopback only and has no auth token yet โ keep it on trusted workstations.
QZ Tray setup (the qz: transport) #
QZ Tray is a local print agent that gives web apps silent, spool-confirmed printing and OS printer status.
- Download the installer for Windows/macOS/Linux from
https://qz.io/download/ and run it. Version 2.2+ bundles its own Java โ
no separate install. The installer also adds a localhost certificate so
wss://localhost:8181works (for Firefox, install QZ Tray after Firefox). - Launch QZ Tray โ an icon appears in the system tray and the agent listens
on
wss://localhost:8181/ws://localhost:8182. - Print with
PrintSettings(printerId: 'qz:')(default printer) or'qz:Printer Name', or callstartPrinterDiscovery()to enumerate agent printers. On the first request QZ Tray shows an Allow/Block prompt โ tick "Remember this decision" to persist it. Signed certificates (silent, no prompt) are a QZ Tray feature configured on their side; this plugin connects in untrusted mode. - Non-standard agent host/port:
WebPrintAgent.configure(endpoint: 'ws://host:port'). - Auto-start: enable "Launch on startup" in the QZ Tray menu (or install it as a Windows service โ see https://qz.io/docs/windows-service).
Testing the web backend #
bash web/build_web.sh # needs emsdk
flutter pub run test -p chrome test/nitro_printing_web_test.dart # dart2js
flutter pub run test -p chrome -c dart2wasm test/nitro_printing_web_test.dart
Development #
Regenerate the bridge code after modifying lib/src/nitro_printing.native.dart:
nitrogen generate && nitrogen link
Run the example app:
cd example
flutter run
Related #
- nitro โ Nitrogen runtime (Flutter port of RN Nitro Modules)
- nitro_generator โ
build_runnercode generator - nitrogen_cli โ CLI scaffold & doctor tool
- nitro_ecosystem repository โ source of the SDK
- Nitro Modules (React Native) โ the original RN library this is ported from
License #
MIT โ see LICENSE.