Files
printer/docs/usage.md
Developer cae04eead5 init
2026-05-18 17:52:16 +08:00

472 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<void> 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<String?>` | 获取平台版本 |
| `enumComPorts()` | `Future<List<String>>` | 枚举可用串口 |
| `enumUsbPorts()` | `Future<List<String>>` | 枚举可用USB端口 |
| `openComPort({...})` | `Future<int>` | 打开串口 |
| `openUsbPort({...})` | `Future<int>` | 打开USB端口 |
| `openComPortWithHandle({...})` | `Future<PrinterPortHandle>` | 打开串口并返回安全句柄 |
| `openUsbPortWithHandle({...})` | `Future<PrinterPortHandle>` | 打开USB端口并返回安全句柄 |
| `closePort(int handle)` | `Future<bool>` | 关闭端口 |
| `isPortOpened(int handle)` | `Future<bool>` | 检查端口是否打开 |
| `setMultiByteMode(int handle)` | `Future<bool>` | 设置多字节编码模式 |
| `setMultiByteEncoding(int, MultiByteEncoding)` | `Future<bool>` | 设置多字节编码类型 |
| `printText(int handle, String text)` | `Future<bool>` | 打印文本 |
| `setAlignment(int, PrinterAlignment)` | `Future<bool>` | 设置文本对齐 |
| `setTextScale(int, {width, height})` | `Future<bool>` | 设置文本缩放 |
| `setTextBold(int handle, bool bold)` | `Future<bool>` | 设置文本加粗 |
| `setTextUnderline(int handle, int level)` | `Future<bool>` | 设置文本下划线 |
| `feedLine(int handle, int numLines)` | `Future<bool>` | 走纸指定行数 |
| `feedDot(int handle, int numDots)` | `Future<bool>` | 走纸指定点数 |
| `halfCutPaper(int handle)` | `Future<bool>` | 半切纸 |
| `fullCutPaper(int handle)` | `Future<bool>` | 全切纸 |
### 枚举类型
#### 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<void>` | 关闭端口,多次调用为 no-op |
### PrinterException 类
| 属性 | 类型 | 说明 |
|------|------|------|
| `code` | `String` | 错误码 |
| `message` | `String` | 错误消息 |
| `details` | `dynamic` | 额外详情 |
---
## 常见问题
### 1. 打印乱码怎么办?
- 确认编码设置与发送的文本编码一致,推荐使用 `MultiByteEncoding.utf8`
- 确认打印机机型是否正确(票据机型使用 `CP_Pos_` 系列函数)
- 检查波特率是否与打印机设置一致
### 2. 端口打开失败?
- 检查端口名称是否正确
- 确认端口未被其他应用占用
- 检查 USB 连接或串口线连接是否正常
### 3. 打印到一半停止?
- 检查电源是否充足(一般需要 2A 电源)
- 检查是否缺纸