Developer Wiki / Printer

Printer workflow basics

Render a bounded page, serialize printer work and make paper, heat, voltage and busy states visible.

Start the stepsBack to Wiki

By the end

A print operation that can be cancelled, retried and diagnosed without leaving the peripheral open.

For Developers adding receipts, labels or proof-of-delivery output to a rugged handheld workflow.

Before you start

Keep the first test small and repeatable.

ModulePrinter
LevelIntermediate
AudienceDevelopers adding receipts, labels or proof-of-delivery output to a rugged handheld workflow.
  • The exact printer option, paper width and supported output types.
  • A test label or receipt that contains no real customer or payment data.
  • A worker or coroutine owner that can serialize print jobs.

Step by step

Build it in 4 deliberate passes.

Each pass produces a checkable result. Keep device-specific calls in the adapter and keep the workflow portable.

  1. 01

    Build one page model

    Keep text, barcode and image elements inside a page with explicit width and height constraints. Do not scatter coordinates across click handlers.

  2. 02

    Check status before rendering

    Treat busy, out-of-paper, over-temperature, under-voltage and driver error as distinct operator states. A generic “print failed” message is not enough for recovery.

  3. 03

    Serialize and cancel

    Disable duplicate submission while the worker owns the printer. A cancelled job must close the resource and leave a clear retry path.

  4. 04

    Validate the physical output

    Measure paper width, barcode readability, feed amount, contrast, heat behavior and battery conditions. Record the printer firmware and accessory configuration.

Copyable pattern / Kotlin

Start with the boundary, then bind the device.

The port owns vendor calls and status mapping. The page model remains usable in a unit test.

print-port.kt

data class PrintJob(
  val title: String,
  val lines: List<String>,
  val barcode: String?,
)

sealed interface PrintResult {
  data object Printed : PrintResult
  data class Blocked(val reason: String) : PrintResult
  data class Failed(val reason: String) : PrintResult
}

interface PrintPort {
  suspend fun print(job: PrintJob): PrintResult
}

suspend fun runPrint(port: PrintPort, job: PrintJob): PrintResult =
  runCatching { port.print(job) }
    .getOrElse { PrintResult.Failed("driver-error") }
Original pattern. No vendor binary is included on this page.

When the happy path breaks

Make recovery part of the first implementation.

Operators experience the failure state, not the API call. Translate device signals into a useful next action.

Printer is busy

Keep the job queued or ask the operator to retry; do not submit parallel page calls.

Out of paper or over-temperature

Show the specific recovery action and wait for a fresh status before retrying.

Barcode is clipped

Check page width, quiet zone and module size for the exact printer configuration.

App is backgrounded

Cancel or finish according to the job policy, then close the printer in the worker.

Before you ship

Use this checklist on the target configuration.

  1. 01

    Print text, one barcode and one image with the target paper width.

  2. 02

    Interrupt the operation and verify the printer is released.

  3. 03

    Test busy, out-of-paper, heat, voltage and driver-error states.

  4. 04

    Confirm no customer, payment or credential data is written to logs or fixtures.

Next step: Add the printer to the same device baseline and Application Validation record as the handheld.

Further reading

Use platform guidance for the parts the device SDK does not own.

These references cover Android lifecycle, broadcast, testing and architecture patterns. Device-specific compatibility still needs a model-level validation record.

Need the exact device binding?

Bring the model, workflow and app build. We will scope the validation.

Validate my application