uni.openBluetoothAdapter失败主因是定位权限未授权,Android需声明并动态申请位置权限,iOS需配置NSLocationWhenInUseUsageDescription,微信小程序还需手动开启定位;搜不到设备应按服务UUID过滤;连接后须确认特征值支持write且用Uint8Array发送ESC/POS指令。
uni.openBluetoothAdapter 失败?先看定位权限有没有被绕过去
android 6.0+ 和 ios 都要求「扫描蓝牙设备」必须有位置权限,不是蓝牙权限本身的问题——uni.openbluetoothadapter 成功不代表能搜到打印机,真正卡住的往往是 uni.startbluetoothdevicesdiscovery 无声失败。
- Android 端必须在
manifest.json的app-plus.distribute.android.permissions里声明ACCESS_FINE_LOCATION(或ACCESS_COARSE_LOCATION),且运行时要主动调用uni.authorize({scope: 'scope.location'}),不能只靠 manifest 声明 - iOS 端除了
bluetooth-central,NSLocationWhenInUseUsageDescription的 description 必须明确写“用于搜索附近蓝牙打印机”,模糊描述(如“提升体验”)会被系统拒绝 - 微信小程序更狠:从 2023 年底起,部分安卓机型(尤其华为、小米)即使开了定位,也得手动进手机「设置 → 应用 → 你的小程序 → 权限 → 定位」点开,否则
onBluetoothDeviceFound根本不触发
怎么确认连的是真·热敏打印机,而不是 BLE 广播的“假设备”
很多开发者扫到一堆名字带 “Printer” 或 “POS” 的设备就直接连,结果写数据没反应——那大概率是广播名伪造的设备,或服务/特征值不匹配。
- 不要只靠
device.name过滤,优先用已知打印机的广播服务 UUID(如佳博常用0000FFE0-0000-1000-8000-00805F9B34FB,得力可能是000018F0-0000-1000-8000-00805F9B34FB),填进uni.startBluetoothDevicesDiscovery的services参数里,能大幅减少干扰设备 - 连接后务必调用
uni.getBLEDeviceServices,再查每个 service 下的characteristics,找properties.write === true且properties.notify === false的特征值(纯发送型,热敏小票机基本都是这种) - 如果
getBLEDeviceCharacteristics返回空数组,说明设备不支持标准 BLE 打印协议,可能走的是经典蓝牙(SPP),uni-app 当前不支持,得换硬件
ESC/POS 指令发不出去?检查字节数组和 write 调用方式
uni.writeBLECharacteristicValue 不是把字符串塞进去就行,它只认 Uint8Array,而且对 iOS/Android 的 buffer 大小限制不同。
- 别用
TextEncoder.encode('ABC')直接转——热敏打印机不认 UTF-8,得按 ASCII 或 GBK 编码(58mm 小票机普遍只吃 ASCII,中文需用 ESC/POS 的0x1B 0x74 0x11切换代码页) - 单次写入长度:Android 一般支持 ≤ 512 字节,iOS 保守起见控制在 ≤ 200 字节,超长必须分包,且每包间隔至少 20ms(用
setTimeout控制),否则丢包 - 必须确保
write前已调用uni.notifyBLECharacteristicValueChange启用 notify(哪怕不用回传),某些固件不启用就不响应写入 - 示例关键片段:
const data = new Uint8Array([0x1B, 0x40, 0x1B, 0x61, 0x01, ...textToBytes('谢谢惠顾'), 0x0A, 0x1D, 0x56, 0x01]); // 初始化+居中+换行+切纸<br>uni.writeBLECharacteristicValue({<br> deviceId: this.deviceId,<br> serviceId: this.serviceId,<br> characteristicId: this.charId,<br> value: data.buffer,<br>});
为什么 iOS 上连得上却打不出字,而 Android 正常?
iOS 对 BLE 特征值写入有隐式校验:如果服务 UUID 是标准蓝牙 SIG 官方定义的(比如 0000180A-0000-1000-8000-00805F9B34FB 设备信息服务),系统会拦截非标准指令;但热敏打印机厂商几乎都用自定义 UUID,所以必须确认你用的 serviceId 和 characteristicId 是从 getBLEDeviceServices 和 getBLEDeviceCharacteristics 动态取的,而不是硬编码。
- 调试技巧:在
getBLEDeviceCharacteristics成功回调里打印所有characteristic.uuid,对比 Android 和 iOS 返回是否一致——iOS 偶尔会返回大写 UUID(如FEE0),Android 返回小写(fee0),字符串比对会失败 - iOS 17+ 对未签名的 BLE 写入增加额外延迟,建议在
write后加await new Promise(r => setTimeout(r, 50))再发下一包,避免粘包 - 如果连特征值都获取不到,检查打印机是否处于“可被发现”模式(有些佳博/得力机型需要长按某键 3 秒才进配对态,不是开机就有 BLE 广播)










