uni-app热敏打印核心是将内容转为打印机可识别的字节流并可靠传输,而非单纯调用API;必须实测确认打印机指令集(ESC/POS/TSPL/CPCL),发错指令会导致空白或卡死。
直接说结论:uni-app 实现热敏打印,核心不是“调用打印机api”,而是「把内容转成打印机能懂的字节流 + 用蓝牙可靠喂给它」。跳过这一步,所有“连接成功”都是假象——你连的是设备,不是打印能力。
怎么确认你的打印机支持哪种指令集
这是最容易被跳过的致命前提。ESC/POS、TSPL、CPCL 互不兼容,发错指令轻则空白,重则卡死或反复进纸。不要依赖“说明书写支持 ESC”,要实测:
- 安卓手机装一个 BLE Scanner(如 nRF Connect),连上打印机后查看服务 UUID 和 characteristic 的 write 属性;
- 向该 characteristic 写入
0x1B 0x40(ESC @,初始化指令)——如果打印机滴一声并走纸,大概率是 ESC/POS; - 若无反应,试试 TSPL 常用指令
SIZE 50 mm, 30 mm(需先转为 UTF-8 字节数组); - 佳博 GP-5890XIII、南方鸿志 58mm 多数默认 ESC/POS;鹭岛宸芯 N80B 需查固件版本,部分出厂是 TSPL 模式。
为什么 html2canvas 在 App 端经常生成空白图片
因为 uni-app 的 webview 或原生渲染层不支持直接读取本地 /static/logo.png 路径。DOM 里 <image src="/static/xxx"></image> 在 html2canvas 里会变成透明区域。
- 必须提前将所有图片转为 Base64:用
uni.getFileSystemManager().readFile读取本地文件,再用uni.arrayBufferToBase64转换; - 网络图片必须加
useCORS: true且服务端返回Access-Control-Allow-Origin: *,否则 canvas 被污染无法导出; - 别用
width/height直接设 canvas 尺寸,优先用 DOM 实际clientWidth/clientHeight,避免缩放失真; - 二维码和文字混排时,确保 canvas 绘制顺序与视图一致,否则二值化后位置偏移。
蓝牙分片发送为什么总是丢数据或乱序
BLE 协议限制单次 write 最大 20 字节(经典蓝牙可到 512),但一张 384×192 的黑白点阵图原始数据就超 9KB。靠 setTimeout 间隔发包是常见错误。
- 必须等上一段写入完成回调(
uni.writeBLECharacteristicValue的 success)再发下一段; - 不能用 for 循环直接切片发送——JS 异步执行会让所有 write 几乎同时触发,底层堆栈溢出;
- 推荐用递归 Promise 链:
sendChunk(data, offset),每次成功后调sendChunk(data, offset + 20); - 某些打印机(如部分驰腾型号)要求每段末尾加
0x0A(换行符)才执行,漏了就卡住不动。
ESC/POS 图片指令怎么写才不糊成一片
热敏打印机不认 PNG,只认“位图点阵 + 控制头”。直接把 canvas getImageData 后的 data 数组塞进去,99% 是黑块。
- 先做灰度:RGB 转 Y = 0.299R + 0.587G + 0.114B;
- 再二值化:用局部自适应阈值(如 Sauvola),别用全局固定值 128,否则阴影处全黑;
- 按打印机宽度对齐:例如 384 像素宽,每行必须是 48 字节(384 ÷ 8),不足补 0;
- 指令头必须完整:
0x1B 0x2A 0x00 0x00 0x00(GS *,后面跟宽度高位/低位、图像数据),少一个字节就拒收。
最常被忽略的一点:不同批次的同型号打印机,固件版本可能让指令行为不一致。比如某次升级后,0x1D 0x56 0x00(切纸)从半切变成全切。上线前务必用真实设备刷三遍以上固件再验证。



















