uni-app 官方蓝牙 API 仅支持 BLE,不支持经典蓝牙 SPP;需先确认打印机类型,SPP 必须用原生插件,BLE 则需通过服务发现获取 serviceId/characteristicId,value 必须为 ArrayBuffer(GBK 编码需特殊处理),并注意平台差异与分包限制。

uni-app 本身不提供底层蓝牙指令发送能力,它只封装了基础的蓝牙 API(如 uni.openBluetoothAdapter、uni.connectBLEDevice 等),真正发指令必须走「连接后的特征值写入」流程。你不能像串口那样直接 write("ESC@"),所有数据都得按 BLE 协议打包进指定 service 和 characteristic。
怎么确认打印机支持的是 BLE 还是经典蓝牙 SPP
这是第一步,错一步全盘失效:
- 用手机系统自带的蓝牙设置页扫描,如果设备名显示为“XX Printer”且能直接配对(无 PIN 码),大概率是经典蓝牙 SPP ——
uni-app的官方蓝牙 API 完全不支持 SPP,必须走原生插件或uni.requireNativePlugin封装BluetoothSocket - 如果设备名带 “BLE”、“IBT”、“HM-10” 等字样,或需先连接再找服务(比如在 nRF Connect 里能看到 0000ffe0-0000-1000-8000-00805f9b34fb 这类 UUID),那就是低功耗蓝牙 BLE —— 可用
uni-app官方 API,但必须手动匹配服务与特征值 - 常见 ESC/POS 打印机(如 ZJ-5890、SP-200)多数是 SPP;而标签打印机(如 Bixolon SRP-350III BLE 版、Zebra ZD420)才提供 BLE 模式,注意看说明书里的通信协议栏
BLE 场景下怎么正确调用 uni.writeBLECharacteristicValue
这个函数看着简单,但参数稍错就静默失败:
-
deviceId必须是uni.getConnectedDevices返回的已连接设备 ID,不是扫描时的deviceId(扫描 ID ≠ 连接 ID) -
serviceId和characteristicId必须来自uni.getBLEDeviceServices+uni.getBLEDeviceCharacteristics的异步结果,不能硬编码 —— 不同品牌打印机 UUID 差异极大,Zijiang 是0000ffe0-0000-1000-8000-00805f9b34fb,Bixolon 是00001101-0000-1000-8000-00805f9b34fb -
value必须是ArrayBuffer,不是字符串或 Uint8Array:用new TextEncoder().encode("Hello").buffer转,GBK 编码要自己处理(ESC/POS 指令多为 GBK,TextEncoder默认 UTF-8,乱码就在这里) - iOS 上必须确保 characteristic 具有
writeWithoutResponse属性,否则会卡住;Android 则建议优先用writeWithResponse便于捕获错误
为什么发了指令但打印机没反应
最常被忽略的三个点:
- 没启用通知(notify)就盲目写入:某些 BLE 打印机要求先对特定 notify characteristic 调用
uni.notifyBLECharacteristicValueChange,否则拒绝接收写入 —— 查看设备文档里的「control point」或「status indicator」特征值 - 分包超长:BLE 单次写入上限通常是 20 字节(iOS)或 512 字节(Android),但很多打印机固件实际限制更严(如 128 字节)。大段文本或图片位图必须切片,每片间隔 ≥ 20ms,否则丢包
- 没等
write成功回调就发下一条:BLE 是异步队列,必须在success回调里触发下一次write,不能靠setTimeout或并行发
ESC/POS 指令怎么转成 ArrayBuffer 发送
别手拼十六进制字符串,容易漏字节:
- 纯文本打印:用
new TextEncoder('gbk').encode("小票内容")(需引入encoding-indexespolyfill 支持 GBK) - 加粗/居中/切纸等控制指令:查打印机手册,例如
ESC @是初始化,对应0x1B 0x40;ESC ! 0x08是加粗,拼成new Uint8Array([0x1B, 0x21, 0x08])再转.buffer - 打印二维码:先用 JS 库(如
qrcode-generator)生成二进制数据,再按打印机要求封装成 ESC/POS 格式(如GS ( k指令族),最后整体转 ArrayBuffer - 调试技巧:用 nRF Connect 连上打印机,手动写入
1B 40,看是否复位;成功后再换你的 App 测试,避免代码和硬件问题混在一起
BLE 指令发送真正的复杂点不在 API 调用,而在「服务发现路径」和「指令编码上下文」——同一台打印机,不同固件版本可能暴露的服务 UUID 不同,同一个 write 调用在 iOS 上成功、Android 上静默失败,往往是因为没做 platform 分支判断。别跳过 getBLEDeviceCharacteristics 的遍历逻辑,也别省略对 characteristic 属性(properties.write / properties.writeWithoutResponse)的校验。











