# Printer 插件使用指南 > 本文档介绍 Flutter Printer 插件的安装、配置和使用方法。该插件封装了 Android `autoreplyprint` SDK,提供了串口/USB 端口管理和票据打印功能。 ## 目录 - [安装](#安装) - [快速开始](#快速开始) - [端口管理](#端口管理) - [票据打印](#票据打印) - [异常处理](#异常处理) - [完整示例](#完整示例) - [API 参考](#api-参考) --- ## 安装 ### 1. 添加依赖 在 `pubspec.yaml` 中添加本地依赖: ```yaml dependencies: printer: path: ../printer # 根据实际路径调整 ``` ### 2. 配置 Android 将 `docs/autoreplyprint.aar` 文件放置到 Android 项目的 `app/libs/` 目录下: ``` your_flutter_app/ └── android/ └── app/ └── libs/ └── autoreplyprint.aar ``` 在 `android/app/build.gradle` 中确保 `libs` 目录被引用: ```gradle dependencies { implementation files('libs/autoreplyprint.aar') // ... 其他依赖 } ``` --- ## 快速开始 ### 基本打印流程 一个完整的打印流程包含三个步骤:**打开端口 → 打印内容 → 关闭端口**。 ```dart import 'package:printer/printer.dart'; final printer = Printer(); // 1. 打开端口 final handle = await printer.openComPort( portName: '/dev/ttyS0', baudRate: 115200, ); // 2. 设置编码并打印文本 await printer.setMultiByteMode(handle); await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8); await printer.setAlignment(handle, PrinterAlignment.center); await printer.printText(handle, 'Hello 中文\n'); await printer.feedLine(handle, 3); // 3. 关闭端口 await printer.closePort(handle); ``` --- ## 端口管理 ### 枚举端口 ```dart // 枚举串口 final comPorts = await printer.enumComPorts(); print('可用串口: $comPorts'); // 枚举USB端口 final usbPorts = await printer.enumUsbPorts(); print('可用USB口: $usbPorts'); ``` ### 打开串口 (COM Port) ```dart final handle = await printer.openComPort( portName: '/dev/ttyS0', // 端口名称(必填) baudRate: 115200, // 波特率(必填),需与打印机保持一致 dataBits: 8, // 数据位,默认8 parity: SerialParity.none, // 校验位,默认无校验 stopBits: SerialStopBits.one, // 停止位,默认1位 flowControl: SerialFlowControl.none, // 流控制,默认无 autoReplyMode: true, // 是否开启自动回传模式 ); ``` **参数说明:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `portName` | `String` | 是 | - | 端口名称,如 `/dev/ttyS0` 或 `COM1` | | `baudRate` | `int` | 是 | - | 波特率,如 `9600`, `19200`, `38400`, `57600`, `115200` | | `dataBits` | `int` | 否 | `8` | 数据位,范围 `[4, 8]` | | `parity` | `SerialParity` | 否 | `none` | 校验位:`none`, `odd`, `even`, `mark`, `space` | | `stopBits` | `SerialStopBits` | 否 | `one` | 停止位:`one`, `onePointFive`, `two` | | `flowControl` | `SerialFlowControl` | 否 | `none` | 流控制:`none`, `xonXoff`, `rtsCts`, `dtrDsr` | | `autoReplyMode` | `bool` | 否 | `true` | 是否开启自动回传模式 | ### 打开 USB 端口 ```dart final handle = await printer.openUsbPort( portName: 'USB001', // 端口名称(必填),可不指定以自动查找 autoReplyMode: true, // 是否开启自动回传模式 ); ``` ### 检查端口状态 ```dart final isOpen = await printer.isPortOpened(handle); if (isOpen) { print('端口已打开'); } ``` ### 关闭端口 ```dart final success = await printer.closePort(handle); ``` ### 使用安全句柄 (推荐) 使用 `PrinterPortHandle` 可以更安全地管理端口资源,避免资源泄漏: ```dart // 打开带句柄的串口 final portHandle = await printer.openComPortWithHandle( portName: '/dev/ttyS0', baudRate: 115200, ); try { // 执行打印操作 await printer.printText(portHandle.handle, 'Hello\n'); } finally { // 确保端口被关闭 await portHandle.close(); } ``` 同样支持 USB 端口: ```dart final portHandle = await printer.openUsbPortWithHandle( portName: 'USB001', ); ``` --- ## 票据打印 ### 打印文本 在打印文本之前,需要先设置多字节编码模式: ```dart // 设置多字节模式 await printer.setMultiByteMode(handle); // 设置编码为 UTF-8(支持中文等多语言字符) await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8); // 打印文本 await printer.printText(handle, 'Hello 中文\n'); ``` **支持的编码类型 (`MultiByteEncoding`):** | 编码 | 值 | 说明 | |------|-----|------| | `gbk` | `0` | GBK 编码(简体中文) | | `utf8` | `1` | UTF-8 编码(Unicode,推荐) | | `big5` | `3` | BIG5 编码(繁体中文) | | `shiftJis` | `4` | Shift-JIS 编码(日文) | | `eucKr` | `5` | EUC-KR 编码(韩文) | ### 设置文本对齐 ```dart // 左对齐 await printer.setAlignment(handle, PrinterAlignment.left); // 居中对齐 await printer.setAlignment(handle, PrinterAlignment.center); // 右对齐 await printer.setAlignment(handle, PrinterAlignment.right); ``` ### 设置文本缩放 宽度和高度缩放值范围为 `1` 到 `8`: ```dart await printer.setTextScale( handle, widthScale: 2, // 宽度放大2倍 heightScale: 2, // 高度放大2倍 ); await printer.printText(handle, 'Large Text\n'); ``` ### 设置文本加粗 ```dart // 开启加粗 await printer.setTextBold(handle, true); await printer.printText(handle, 'Bold Text\n'); // 关闭加粗 await printer.setTextBold(handle, false); ``` ### 设置文本下划线 ```dart // 0 = 无下划线 // 1 = 1点下划线 // 2 = 2点下划线 await printer.setTextUnderline(handle, 1); await printer.printText(handle, 'Underlined Text\n'); ``` ### 走纸 ```dart // 走纸指定行数 await printer.feedLine(handle, 5); // 走纸指定点数 await printer.feedDot(handle, 100); ``` ### 切纸 ```dart // 半切(虚线切,纸张不完全分离) await printer.halfCutPaper(handle); // 全切(实线切,纸张完全分离) await printer.fullCutPaper(handle); ``` --- ## 异常处理 所有端口打开操作在失败时会抛出 `PrinterException`: ```dart try { final handle = await printer.openComPort( portName: '/dev/ttyS0', baudRate: 115200, ); } on PrinterException catch (e) { print('端口打开失败: ${e.code} - ${e.message}'); } ``` `PrinterException` 包含以下信息: | 属性 | 类型 | 说明 | |------|------|------| | `code` | `String` | 机器可读的错误码,如 `INVALID_ARGUMENT`, `PORT_OPEN_FAILED` | | `message` | `String` | 人类可读的错误消息 | | `details` | `dynamic` | 额外的错误详情(可能为 null) | --- ## 完整示例 以下是一个完整的票据打印示例: ```dart import 'package:printer/printer.dart'; /// 打印收据示例 Future printReceipt() async { final printer = Printer(); PrinterPortHandle? portHandle; try { // 1. 枚举可用端口 final comPorts = await printer.enumComPorts(); if (comPorts.isEmpty) { print('没有可用的串口'); return; } // 2. 打开第一个可用端口 portHandle = await printer.openComPortWithHandle( portName: comPorts.first, baudRate: 115200, ); final handle = portHandle.handle; // 3. 设置编码 await printer.setMultiByteMode(handle); await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8); // 4. 打印标题(居中、加粗、放大) await printer.setAlignment(handle, PrinterAlignment.center); await printer.setTextBold(handle, true); await printer.setTextScale(handle, widthScale: 2, heightScale: 2); await printer.printText(handle, '收据标题\n'); // 5. 重置样式并打印内容 await printer.setTextBold(handle, false); await printer.setTextScale(handle, widthScale: 1, heightScale: 1); await printer.setAlignment(handle, PrinterAlignment.left); await printer.printText(handle, '商品名称 数量 价格\n'); await printer.printText(handle, '----------------------------\n'); await printer.printText(handle, '商品A 2 ¥20.00\n'); await printer.printText(handle, '商品B 1 ¥15.00\n'); await printer.printText(handle, '----------------------------\n'); await printer.printText(handle, '总计: ¥35.00\n'); // 6. 走纸并切纸 await printer.feedLine(handle, 5); await printer.halfCutPaper(handle); print('打印完成'); } on PrinterException catch (e) { print('打印失败: ${e.code} - ${e.message}'); } finally { // 7. 确保端口关闭 await portHandle?.close(); } } ``` --- ## API 参考 ### Printer 类 | 方法 | 返回值 | 说明 | |------|--------|------| | `getPlatformVersion()` | `Future` | 获取平台版本 | | `enumComPorts()` | `Future>` | 枚举可用串口 | | `enumUsbPorts()` | `Future>` | 枚举可用USB端口 | | `openComPort({...})` | `Future` | 打开串口 | | `openUsbPort({...})` | `Future` | 打开USB端口 | | `openComPortWithHandle({...})` | `Future` | 打开串口并返回安全句柄 | | `openUsbPortWithHandle({...})` | `Future` | 打开USB端口并返回安全句柄 | | `closePort(int handle)` | `Future` | 关闭端口 | | `isPortOpened(int handle)` | `Future` | 检查端口是否打开 | | `setMultiByteMode(int handle)` | `Future` | 设置多字节编码模式 | | `setMultiByteEncoding(int, MultiByteEncoding)` | `Future` | 设置多字节编码类型 | | `printText(int handle, String text)` | `Future` | 打印文本 | | `setAlignment(int, PrinterAlignment)` | `Future` | 设置文本对齐 | | `setTextScale(int, {width, height})` | `Future` | 设置文本缩放 | | `setTextBold(int handle, bool bold)` | `Future` | 设置文本加粗 | | `setTextUnderline(int handle, int level)` | `Future` | 设置文本下划线 | | `feedLine(int handle, int numLines)` | `Future` | 走纸指定行数 | | `feedDot(int handle, int numDots)` | `Future` | 走纸指定点数 | | `halfCutPaper(int handle)` | `Future` | 半切纸 | | `fullCutPaper(int handle)` | `Future` | 全切纸 | ### 枚举类型 #### SerialParity (串口校验位) | 值 | 说明 | |----|------| | `none` | 无校验 | | `odd` | 奇校验 | | `even` | 偶校验 | | `mark` | 标记校验 | | `space` | 空白校验 | #### SerialStopBits (串口停止位) | 值 | 说明 | |----|------| | `one` | 1位停止位 | | `onePointFive` | 1.5位停止位 | | `two` | 2位停止位 | #### SerialFlowControl (串口流控制) | 值 | 说明 | |----|------| | `none` | 无流控 | | `xonXoff` | XON/XOFF 软件流控 | | `rtsCts` | RTS/CTS 硬件流控 | | `dtrDsr` | DTR/DSR 硬件流控 | #### PrinterAlignment (打印对齐) | 值 | 说明 | |----|------| | `left` | 左对齐 | | `center` | 居中对齐 | | `right` | 右对齐 | #### MultiByteEncoding (多字节编码) | 值 | 说明 | |----|------| | `gbk` | GBK 编码(简体中文) | | `utf8` | UTF-8 编码(推荐) | | `big5` | BIG5 编码(繁体中文) | | `shiftJis` | Shift-JIS 编码(日文) | | `eucKr` | EUC-KR 编码(韩文) | ### PrinterPortHandle 类 | 属性/方法 | 类型 | 说明 | |-----------|------|------| | `handle` | `int` | 整数端口句柄 | | `isValid` | `bool` | 端口是否仍然有效 | | `close()` | `Future` | 关闭端口,多次调用为 no-op | ### PrinterException 类 | 属性 | 类型 | 说明 | |------|------|------| | `code` | `String` | 错误码 | | `message` | `String` | 错误消息 | | `details` | `dynamic` | 额外详情 | --- ## 常见问题 ### 1. 打印乱码怎么办? - 确认编码设置与发送的文本编码一致,推荐使用 `MultiByteEncoding.utf8` - 确认打印机机型是否正确(票据机型使用 `CP_Pos_` 系列函数) - 检查波特率是否与打印机设置一致 ### 2. 端口打开失败? - 检查端口名称是否正确 - 确认端口未被其他应用占用 - 检查 USB 连接或串口线连接是否正常 ### 3. 打印到一半停止? - 检查电源是否充足(一般需要 2A 电源) - 检查是否缺纸