更新记录

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 = EAN13
  • barcode_height:1–255 点,常用 60–100
  • barcode_width:2–6,模块宽度
  • qr_ec:0 = L、1 = M(默认)、2 = Q、3 = H
  • qr_module_size:1–16,58mm 纸建议 5–6,80mm 纸建议 7–8
  • printImage 的 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 处理。

十、注意事项

  1. 必须有真实串口硬件。普通手机、平板没有 /dev/ttyS* 节点,只能调通接口逻辑,无法实际打印。
  2. 切纸指令仅对带切刀的机型有效,无切刀机型请勿调用 cutPaper 或 printEndNumber({ cut: true })。
  3. 一个串口同一时刻只能被一个进程占用,避免与其他串口工具同时打开。
  4. 插件按 ESC/POS 标准指令实现,个别品牌(如部分便携机)使用私有指令集,可用 printRaw() 自行下发。
  5. 自定义基座打包时的 ABI 需覆盖目标设备。常见一体机为 arm64-v8a,老设备为 armeabi-v7a。
  6. 打印数据量大的场景(如位图),建议先用 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() 的返回内容
  • 实际打印效果照片或异常日志

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

无

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。