Implementing Document Printing from Mobile Applications
Printing from mobile app — task underestimated until first crash report from zero printers or inability to print PDF on competing vendor printer. Proper implementation requires understanding three independent channels: system Print Framework, AirPrint/Mopria, direct printing via vendor SDK.
Android: Print Framework and Limitations
Android provides PrintManager + PrintDocumentAdapter — standard path with system printer selection. Works via PrintService plugins: Google Cloud Print obsolete, Mopria Print Service — current standard for Wi-Fi printers.
For PDF printing:
val printManager = getSystemService(Context.PRINT_SERVICE) as PrintManager
val jobName = "Document_${System.currentTimeMillis()}"
printManager.print(jobName, object : PrintDocumentAdapter() {
override fun onLayout(oldAttr: PrintAttributes?, newAttr: PrintAttributes,
cancellationSignal: CancellationSignal,
callback: LayoutResultCallback, extras: Bundle?) {
if (cancellationSignal.isCanceled) { callback.onLayoutCancelled(); return }
val info = PrintDocumentInfo.Builder(jobName)
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(pageCount)
.build()
callback.onLayoutFinished(info, oldAttr != newAttr)
}
override fun onWrite(pages: Array<out PageRange>, destination: ParcelFileDescriptor,
cancellationSignal: CancellationSignal, callback: WriteResultCallback) {
// Write PDF bytes to destination.fileDescriptor
}
}, null)
Main issue: PrintDocumentAdapter works with ParcelFileDescriptor. Pass ready PDF — copy bytes via FileOutputStream. PdfDocument from Android SDK suits simple docs; for complex — iText7 or HTML rendering via WebView.createPrintDocumentAdapter().
WebView.createPrintDocumentAdapter() — underrated tool. HTML + CSS → WebView → PrintDocumentAdapter. Supports @media print, page-break-before, @page { size: A4 }. For invoice templates, acts, labels — simpler than Canvas drawing.
iOS: AirPrint and UIPrintInteractionController
iOS printing via UIPrintInteractionController. Supports UIPrintInfo for setup (duplex, orientation) and multiple content types: UIPrintingItem (file URL), UIPrintPageRenderer (custom rendering).
let printController = UIPrintInteractionController.shared
let printInfo = UIPrintInfo(dictionary: nil)
printInfo.jobName = "Invoice"
printInfo.outputType = .general
printController.printInfo = printInfo
printController.printingItem = pdfURL // URL to local PDF
printController.present(animated: true)
AirPrint works without setup — iOS discovers printers automatically via Bonjour. Issue: printer must support AirPrint. Most corporate Canon, HP, Epson — support. Old models — no.
Direct Printing on Label Printers
Warehouse and retail apps need Zebra ZPL or TSC TSPL printing. System Print Framework won't help — need direct TCP/IP or Bluetooth.
Zebra Link-OS SDK for Android: ZebraPrinter via Connection (TCP or Bluetooth). Send ZPL template:
val connection = TcpConnection("192.168.1.100", 9100)
connection.open()
val printer = ZebraPrinterFactory.getInstance(connection)
printer.sendCommand("^XA^FO50,50^A0N,30,30^FDHello World^FS^XZ")
connection.close()
ZPL templates conveniently stored on server, fill via String.format() or Mustache. For dynamic barcodes — ^BC (Code128) or ^BQ (QR) ZPL commands.
Approach Selection by Scenario
| Scenario | Approach |
|---|---|
| A4 documents (invoices, acts) | WebView → PrintDocumentAdapter / AirPrint |
| PDF from server | PrintDocumentAdapter with ParcelFileDescriptor / UIPrintInteractionController |
| Zebra ZPL labels | Zebra Link-OS SDK, direct TCP |
| Thermal printer receipts | ESCPOS via Bluetooth or TCP |
| POS receipts (54-ФЗ) | ATOL SDK / Evotry SDK |
Document printing implementation: 1–3 weeks depending on printer type and template complexity.







