更新记录
1.0.0(2026-11-15)
首次发布
平台兼容性
uni-app(4.0)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | × | × | - | - | 4.4 | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.0)
| Chrome | Safari | Android | Android插件版本 | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|---|
| × | × | 5.0 | 1.0.0 | × | × | × |
安卓串口 ESC/POS 打印插件 · 使用说明
一、插件简介
本插件让 Android 设备通过板载串口直连热敏小票打印机。串口层由 JNI + termios 原生实现,打印层按 ESC/POS 指令集生成小票字节,适用于收银机、自助终端、排队叫号机、称重打票机、后厨打印机等一体化设备。
插件以 UTS 编写,同一份代码同时兼容 uni-app(Vue2 / Vue3) 与 uni-app x。所有接口同步调用,统一返回 { code, msg, data };不依赖任何第三方库,不申请网络、存储、定位等权限。
| 项目 | 说明 |
|---|---|
| 插件 ID | zzzili-serialprint |
| 插件类型 | UTS 插件(API 插件) |
| 最低系统 | Android 5.0(API 21) |
| 兼容平台 | uni-app(Vue2 / Vue3)、uni-app x |
| 支持架构 | armeabi-v7a、arm64-v8a、x86、x86_64 |
| 接口数量 | 41 个方法 |
| 第三方依赖 | 无 |
| 权限申请 | 无 |
本插件只支持 Android App,不支持 H5、小程序、iOS、鸿蒙。
二、功能特性
串口通信
- 自动枚举
/dev/ttyS0–/dev/ttyS7、/dev/ttyUSB*、/dev/ttyACM*,返回每个节点的读写权限状态 - 波特率 1200–4000000(支持非标准自定义波特率)、数据位 5/6/7/8、校验 NONE/ODD/EVEN/SPACE/MARK、停止位 1/2、流控 NONE/RTS-CTS/XON-XOFF
- 支持同步读、十六进制原样收发、缓冲区清空
- 可作为通用串口模块,与电子秤、扫码枪、PLC 等设备通信
小票打印
- 中文 GBK 编码,按「全角字符占 2 列」计算显示宽度,58mm(32 列)/ 80mm(48 列)纸宽自动排版
- 加粗、字号 1–8 倍、下划线、反白、左中右对齐、字体 A/B、代码页切换
- 双列(左右贴边)、三列(左中右)、分割线、制表空格
- 条形码:CODE128 / CODE93 / CODE39 / EAN13,高度与模块宽度可调
- 二维码:L/M/Q/H 四级纠错,模块点大小 1–16 可调,走打印机内置
GS ( k - 图片:Base64 自动二值化后按
GS v 0光栅输出 - 走纸、切纸(全切 / 半切)、开钱箱、蜂鸣
性能与易用性
printReceipt():一个 ops 数组输出整张小票,一次写入beginBatch()/endBatch():多次调用合并为一次串口写入printRaw():任意 ESC/POS 字节直发,指令集之外的机型特性也能支持
三、安装与引入
3.1 插件市场安装
在插件详情页点击「使用 HBuilderX 导入插件」,选择目标项目即可,插件会被放入项目的 uni_modules/zzzili-serialprint/ 目录。
3.2 手动安装
把 uni_modules/zzzili-serialprint/ 整个目录复制到项目根目录的 uni_modules 下,保持目录层级不变。
3.3 必须使用自定义基座
插件内含原生串口库,标准基座不包含该插件。请通过菜单「运行 → 运行到手机或模拟器 → 制作自定义基座」,用自定义基座运行。否则 import 会失败或方法为 undefined。
3.4 自带示例页,可先跑通再接入
插件内置一份完整演示页:uni_modules/zzzili-serialprint/utssdk/example.vue,覆盖「枚举串口 → 选波特率 → 连接 → 打印文字 / 二维码 / 整张小票 → 切纸 / 开钱箱」全流程。
把该文件复制到项目的 pages/example/example.vue,在 pages.json 的 pages 数组加一项:
{ "path": "pages/example/example", "style": { "navigationBarTitleText": "串口打印演示" } }
用自定义基座运行到真机,即可看到设备列表与打印按钮,无需改一行代码。接入自己的业务时,参考该页的调用顺序即可。
3.5 引入方式
import {
listDevices,
callNativePrintInitSerialConnectDevices,
callNativePrintSerialClose,
printText,
printReceipt
} from '@/uni_modules/zzzili-serialprint'
只能引入到插件根目录。写成 @/uni_modules/zzzili-serialprint/utssdk/app-android/index.uts 会被当作普通 JS 编译而报错。
3.6 调用与返回
UTS 插件为同步调用,直接返回结果对象,不需要 callback:
const r = callNativePrintInitSerialConnectDevices({
device: '/dev/ttyS4',
baudRate: 9600
})
if (r.code === 0) {
console.log('已连接', r.data.device)
} else {
console.error(r.msg)
}
四、五分钟跑通
import {
listDevices,
callNativePrintInitSerialConnectDevices,
printAlignment, setTextBold, setFontSize, printText,
printThreeColumn, printDivider, printQR, printEndNumber,
callNativePrintSerialClose
} from '@/uni_modules/zzzili-serialprint'
// 1. 查看可用串口(首次接入建议先跑这一步)
const dev = listDevices()
console.log('串口列表', dev.data)
// 2. 打开串口(默认 /dev/ttyS4、9600、8N1、无流控)
const opened = callNativePrintInitSerialConnectDevices({
device: '/dev/ttyS4',
baudRate: 9600
})
if (opened.code !== 0) {
console.error(opened.msg)
} else {
// 3. 打印
printAlignment({ align_mode: 1 })
setTextBold({ font_bold: true })
setFontSize({ font_size: 1 })
printText({ content: '测试小票\n' })
setTextBold({ font_bold: false })
setFontSize({ font_size: 0 })
printAlignment({ align_mode: 0 })
printThreeColumn({ left_text: '商品', center_text: '数量', right_text: '金额' })
printDivider({ char: '-' })
printThreeColumn({ left_text: '苹果', center_text: '2', right_text: '12.00' })
printQR({ qr_text: 'https://example.com', qr_module_size: 6 })
printEndNumber({ feed_lines: 4, cut: true })
// 4. 关闭
callNativePrintSerialClose(null)
}
所有方法返回 { code, msg, data },判断 code === 0 即可。
五、API 一览
方法签名为 方法名(options),同步返回 { code, msg, data }。参数为对象,未传的字段取默认值。
5.1 连接管理
| 方法 | 关键参数 | 说明 |
|---|---|---|
callNativePrintInitSerialConnectDevices |
device, baudRate, dataBits, parity, stopBits, flowControl, readTimeoutMs, autoPermissionFix |
打开串口并下发 ESC @ 初始化打印机 |
callNativePrintSerialClose |
— | 关闭串口,返回关闭前状态快照 |
listDevices |
— | 枚举串口节点及读写权限 |
getState |
— | 连接状态、当前样式、批量模式、最近错误 |
getLastError |
— | 最近一次错误详情 |
getVersion |
— | 插件版本、插件 ID |
连接参数说明:
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
device |
string | /dev/ttyS4 |
串口节点路径 | |
baudRate |
number | 9600 | 波特率 | |
dataBits |
number | 8 | 5 / 6 / 7 / 8 | |
parity |
number | string | 0 | 0/NONE、1/ODD、2/EVEN、3/SPACE、4/MARK |
stopBits |
number | 1 | 1 / 2 | |
flowControl |
number | string | 0 | 0/NONE、1/RTS_CTS、2/XON_XOFF |
readTimeoutMs |
number | 200 | 读取超时 | |
autoPermissionFix |
boolean | false | 已 root 设备自动 chmod 666 节点 |
5.2 样式设置
| 方法 | 关键参数 | 对应指令 |
|---|---|---|
printState |
— | ESC @ 复位打印机 |
setFontSize |
font_size: 0–7,即 1–8 倍 |
GS ! n |
setTextBold |
font_bold: true / false |
ESC E n |
setUnderline |
underline: 0/1/2 |
ESC - n |
printAlignment |
align_mode: 0/1/2,左 / 中 / 右 |
ESC a n |
setFont |
font: 0/1,字体 A / B |
ESC M n |
setInvert |
invert: true / false,反白 |
GS B n |
setCodePage |
code_page: 0–255 |
ESC t n |
setCharset |
charset: "GBK" / "UTF-8" |
文本编码,仅影响字节生成 |
setLineWidth |
line_width: 32 / 48 |
排版列宽 |
setChineseMode |
chinese_mode: true / false |
FS & / FS . |
setConfig |
上述参数任意组合,另含 qr_ec, qr_module_size, qr_model_command, barcode_hri, barcode_type, barcode_auto_center |
一次性批量配置 |
setConfig 示例:
setConfig({
line_width: 48,
charset: 'GBK',
chinese_mode: true,
qr_ec: 1,
qr_module_size: 6,
barcode_type: 73,
barcode_auto_center: true
})
5.3 内容打印
| 方法 | 关键参数 | 说明 |
|---|---|---|
printText |
content |
打印文本,不换行 |
printTextLine |
content |
打印文本并换行 |
printLine |
line_length |
打印 N 个换行 |
printTabSpace |
tab_length |
打印 N 个空格 |
printDivider |
char |
按纸宽画分割线 |
printTwoColumn |
title, content |
双列,右侧贴边 |
printThreeColumn |
left_text, center_text, right_text |
三列,按纸宽三等分 |
printBarcode |
barcode_text, barcode_type, barcode_height, barcode_width |
条形码 |
printQR |
qr_text, qr_module_size, qr_ec, qr_width, qr_height |
二维码 |
printImage |
base64, width, threshold |
位图 |
feed |
lines |
走纸,ESC d n |
cutPaper |
partial, feed_lines |
切纸,全切 / 半切 |
openDrawer |
— | 开钱箱,ESC p |
printBeep |
times, duration |
蜂鸣 |
printEndNumber |
feed_lines, cut, partial |
结束标签(走纸 + 可选切纸) |
printRaw |
hex / base64 / text / charset |
直发任意 ESC/POS 字节 |
参数取值:
barcode_type:73= CODE128(默认)、72= CODE93、4= CODE39、2= EAN13barcode_height:1–255 点,常用 60–100barcode_width:2–6,模块宽度qr_ec:0= L、1= M(默认)、2= Q、3= Hqr_module_size:1–16,58mm 纸建议 5–6,80mm 纸建议 7–8printImage的threshold:二值化阈值,默认 128;width为缩放后的目标宽度,58mm 纸建议 384,80mm 纸建议 576
5.4 一次成型与批量
| 方法 | 说明 |
|---|---|
printReceipt |
{ ops: [...] } 输出整张小票;send: false 时只返回字节不发送 |
beginBatch / endBatch |
批量模式,期间指令只累积,endBatch 时一次性写入 |
printReceipt 支持的 op 类型:
| type | 关键字段 |
|---|---|
init |
— |
align |
mode |
bold |
value |
underline |
value |
fontSize |
level |
font |
value |
invert |
value |
charset |
value |
lineWidth |
value |
text |
content |
textLine |
content |
line |
count |
space |
count |
feed |
lines |
twoColumn |
title, content |
threeColumn |
left, center, right |
divider |
char |
barcode |
text, height, width |
qr |
text, module_size, ec 或 width, height |
raw |
hex |
cut |
partial, lines |
drawer |
— |
beep |
times |
printReceipt 返回:
{
code: 0,
msg: '生成 892 字节',
data: {
length: 892,
hex: '1B40...',
base64: 'G0A...',
sent: true
}
}
5.5 通用串口
| 方法 | 关键参数 | 说明 |
|---|---|---|
writeRaw |
hex / base64 / text、charset |
绕过指令构造器直接写串口 |
readRaw |
max_bytes, timeout |
同步读,返回 { hex, length } |
flush |
queue: 0/1/2 |
清输入 / 清输出 / 全清 |
setCustomBaudRate |
baudRate |
设置非标准波特率 |
六、完整小票示例
6.1 推荐写法:一次调用完成
import { printReceipt } from '@/uni_modules/zzzili-serialprint'
const r = printReceipt({
ops: [
{ type: 'init' },
{ type: 'align', mode: 1 },
{ type: 'bold', value: true },
{ type: 'fontSize', level: 1 },
{ type: 'textLine', content: '美味餐厅' },
{ type: 'bold', value: false },
{ type: 'fontSize', level: 0 },
{ type: 'textLine', content: '订单号:20261115001' },
{ type: 'align', mode: 0 },
{ type: 'divider' },
{ type: 'threeColumn', left: '商品', center: '数量', right: '金额' },
{ type: 'divider' },
{ type: 'threeColumn', left: '宫保鸡丁', center: '1', right: '38.00' },
{ type: 'threeColumn', left: '米饭', center: '2', right: '4.00' },
{ type: 'divider' },
{ type: 'twoColumn', title: '合计:', content: '42.00' },
{ type: 'line', count: 1 },
{ type: 'align', mode: 1 },
{ type: 'qr', text: 'https://example.com/order/20261115001', module_size: 6 },
{ type: 'line', count: 1 },
{ type: 'align', mode: 0 },
{ type: 'cut', partial: false, lines: 4 }
]
})
console.log(r.code, r.msg)
整张小票一次性生成字节并写入串口,比逐条调用快一个量级。
6.2 只生成字节,不打印
用于把字节转发到蓝牙、网口打印机,或落盘存档:
const r = printReceipt({
ops: [ /* 同上 */ ],
send: false
})
console.log('小票共', r.data.length, '字节')
// r.data.base64 可直接交给蓝牙打印机写入
6.3 打印图片(如店铺 Logo)
// base64 带不带 data URI 前缀都可以
printImage({
base64: 'data:image/png;base64,iVBORw0K...',
width: 384,
threshold: 128
})
建议先把图片缩放到纸宽像素:58mm 纸 384px,80mm 纸 576px。
6.4 批量模式
import {
beginBatch, endBatch,
printTextLine, printDivider, feed
} from '@/uni_modules/zzzili-serialprint'
beginBatch()
printTextLine({ content: '第一批' })
printDivider({ char: '=' })
printTextLine({ content: '第二批' })
feed({ lines: 3 })
const r = endBatch() // 此处一次性写入串口
循环里逐条打印时,用批量模式能显著减少写入次数,避免半张停纸。
七、串口通信示例
插件也可作为通用串口模块,与电子秤、扫码枪、PLC 等设备通信。
import {
callNativePrintInitSerialConnectDevices,
writeRaw, readRaw
} from '@/uni_modules/zzzili-serialprint'
// 打开串口
callNativePrintInitSerialConnectDevices({
device: '/dev/ttyS3',
baudRate: 9600,
dataBits: 8,
parity: 'NONE',
stopBits: 1,
flowControl: 'NONE'
})
// 发送十六进制指令(Modbus 读保持寄存器)
writeRaw({ hex: '01 03 00 00 00 02 C4 0B' })
// 同步读取应答
const rd = readRaw({ max_bytes: 64, timeout: 300 })
console.log('应答', rd.data.hex, rd.data.length)
// 或轮询
setInterval(() => {
const r = readRaw({ max_bytes: 64, timeout: 50 })
if (r.code === 0 && r.data.length > 0) {
console.log('收到', r.data.hex)
}
}, 200)
发送文本(会被按 charset 编码):
writeRaw({ text: 'AT\r\n', charset: 'ASCII' })
八、返回结构与错误码
成功:
{
"code": 0,
"msg": "串口已连接:/dev/ttyS4",
"data": { "connected": true, "baudRate": 9600 }
}
| code | 含义 | 常见原因 |
|---|---|---|
| 0 | 成功 | — |
| -1 | 串口未连接 | 未调用初始化,或连接已断开 |
| -2 | 参数错误 | 波特率非法、device 为空、ops 结构错误 |
| -3 | IO / 设备错误 | 节点不存在、被占用、写入失败 |
| -99 | 其他异常 | 未捕获异常,详见 getLastError() |
失败时 msg 会带系统级原因,例如:
打开串口 /dev/ttyS4 失败: Permission denied (errno=13)
getState() 返回示例:
{
code: 0,
msg: 'ok',
data: {
connected: true,
device: '/dev/ttyS4',
baudRate: 9600,
dataBits: 8,
parity: 0,
stopBits: 1,
flowControl: 0,
bytesWritten: 1024,
bytesRead: 0,
connectedAt: 1763000000000,
uptimeMs: 3200,
style: { fontSize: 0, bold: false, align: 0, lineWidth: 32, charset: 'GBK' },
batchMode: false,
lastError: ''
}
}
九、常见问题
1. 提示找不到模块,或方法为 undefined
UTS 插件含原生库,标准基座不包含。请制作自定义基座后运行;同时确认 uni_modules/zzzili-serialprint/ 目录层级正确,import 路径只写到插件根目录。
2. 打开串口报 Permission denied (errno=13)
串口节点默认属主为 root:root,普通应用没有读写权限。四种解法:
- 设备已 root:连接时传
autoPermissionFix: true,插件会执行su -c chmod 666 <节点> - 系统预装:在
init.rc中为节点设置chmod 0666 - 有系统签名:用
android:sharedUserId="android.uid.system"打系统应用 - 长期方案:厂商在
ueventd.rc中固化权限
先跑 listDevices() 看目标节点的 readable / writable 字段,能直接定位。
3. 中文打印成乱码
确认打印机支持 GBK,绝大多数国产热敏机默认支持。繁体或日文机型可用 setCharset 换编码,或用 setCodePage 切换打印机字符表。乱码也可能是波特率不匹配导致,可换 38400 / 115200 试。
4. 二维码打印不出来
部分老机型固件不认 GS ( k。可改用 printImage() 传自绘二维码位图,或尝试 setConfig({ qr_model_command: true }) 补发模型选择指令。
5. 双列 / 三列对不齐
纸宽设置不对。58mm 纸为 32 列、80mm 纸为 48 列,用 setLineWidth({ line_width: 48 }) 调整。中文按 2 列计算,含大量中文时列宽会更紧张。
6. 打了半张就停
多为供电不足或写入过快。可在关键段落之间插入 feed({ lines: 1 }) 稍作间隔,或改用 beginBatch() 合并写入,避免高频小包。
7. 想在模拟器上调试
插件已内置 x86 架构,模拟器可直接使用。若 utssdk/app-android/config.json 的 abis 中移除了 x86,需加回并重新打自定义基座。
8. 能不能在 uni-app x 里用
可以。UTS 插件同时支持 uni-app 与 uni-app x,调用方式一致。uni-app x 项目里注意 r.data 的类型断言,取嵌套字段时按 UTSJSONObject 处理。
十、注意事项
- 必须有真实串口硬件。普通手机、平板没有
/dev/ttyS*节点,只能调通接口逻辑,无法实际打印。 - 切纸指令仅对带切刀的机型有效,无切刀机型请勿调用
cutPaper或printEndNumber({ cut: true })。 - 一个串口同一时刻只能被一个进程占用,避免与其他串口工具同时打开。
- 插件按 ESC/POS 标准指令实现,个别品牌(如部分便携机)使用私有指令集,可用
printRaw()自行下发。 - 自定义基座打包时的 ABI 需覆盖目标设备。常见一体机为 arm64-v8a,老设备为 armeabi-v7a。
- 打印数据量大的场景(如位图),建议先用
beginBatch()或printReceipt()合并,再一次性写入。
十一、版本记录
v2.0.0
- 插件形态改为 UTS 插件,同一份代码兼容 uni-app 与 uni-app x
- 41 个 API,同步调用,统一返回
{ code, msg, data } - 串口层保持 JNI + termios 实现:设备枚举、全参数配置、原始收发、自定义波特率
- 打印层覆盖文本、中文、样式、双列三列、条形码、二维码、位图、走纸切纸、钱箱、蜂鸣
- 提供
printReceipt一次性小票与beginBatch/endBatch批量写入
十二、技术支持
接入中遇到机型适配问题,请提供以下信息,便于快速定位:
- 设备型号、Android 版本
- 打印机型号、接口类型(串口 / TTL)
listDevices()返回的串口列表getState()与getLastError()的返回内容- 实际打印效果照片或异常日志

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 133
赞赏 0
下载 12765807
赞赏 1959
赞赏
京公网安备:11010802035340号