摩拜单车蓝牙开锁需严格遵循BLE状态机流程:寻车广播→随机数挑战→加密响应→开锁指令写入;uni-app实现时须按序执行,漏步即报errCode=10006或空数据。

摩拜单车这类蓝牙开锁不是“连上就发指令”,而是典型的 BLE 协议状态机驱动流程:寻车广播 → 随机数挑战 → 加密响应 → 开锁指令写入。uni-app 能做,但必须严格按顺序走完每一步,漏掉任意环节都会报 errCode=10006 或返回空数据。
uni.openBluetoothAdapter 失败时先别改代码
90% 的“开不了”卡在系统级门槛上,不是逻辑问题:
- iOS 必须在
manifest.json的app-plus → permissions中勾选「蓝牙」,并填写NSBluetoothAlwaysUsageDescription;Xcode 打包后还要手动开启Background Modes → Bluetooth Central - Android 12+(API 31+)必须动态申请两个权限:
scope.bluetoothScan和scope.bluetoothConnect——uni.authorize({scope: 'scope.bluetooth'})已失效,必须分开调 - Android API ≤ 30 还要
scope.location,因为系统把扫描归为定位行为;华为/小米等厂商会静默关闭扫描,得弹窗提醒用户手动打开「位置信息」和「蓝牙扫描」开关 - 调用
uni.openBluetoothAdapter前,务必先用uni.getBluetoothAdapterState确认available: true,否则它会静默失败或返回errCode=10001
startBluetoothDevicesDiscovery 搜不到“摩拜锁”的原因
摩拜类设备通常不广播 service UUID,只靠特定广播名(如 "MoBike" 或固定 MAC 前缀)识别,但 uni-app 默认过滤掉无 service 的设备:
- 必须显式传空数组:
{services: []},否则 iOS 15+ 和部分 Android 会直接忽略 -
uni.onBluetoothDeviceFound必须在startBluetoothDevicesDiscovery成功回调内注册,且不能用箭头函数(this绑定失效会导致监听丢失) - 广播是间歇性的(比如每 2 秒一次),所以
duration至少设 10 秒,别指望“秒出” - 真机调试时禁用 HBuilderX 的 USB 连接调试,改用 Wi-Fi 调试或离线打包,否则蓝牙 API 可能被拦截
createBLEConnection 后读不到随机数?流程断在服务发现
连接成功 ≠ 能通信。摩拜协议第一步是读取一个特征值(通常是 0000ffe1-0000-1000-8000-00805f9b34fb)获取随机数,但这个特征值藏在某个 service 下:
- 必须监听
uni.onBLEConnectionStateChange,确认connected: true后再执行下一步 - 调
uni.getBLEDeviceServices({deviceId}),注意筛选isPrimary: true的主服务(别用services[0]硬取) - 再用该服务的
uuid调uni.getBLEDeviceCharacteristics,检查目标 characteristic 的properties.read === true(大小写敏感) - 启用通知不是必须的,但读随机数必须用
uni.readBLECharacteristicValue,且serviceId和characteristicId必须来自上一步返回,不能手写
writeBLECharacteristicValue 写不开锁?校验加密逻辑是否本地完成
摩拜类协议要求客户端用收到的随机数 + 密钥 + 时间戳做 AES 加密,生成指令体(如 7B5B01610060),再写入另一个可写的 characteristic:
- 写之前必须确认该 characteristic 的
properties.write === true,有些设备还要求properties.writeWithoutResponse - 指令是十六进制字符串,需转成 ArrayBuffer:
new Uint8Array([0x7b, 0x5b, ...]),别直接传字符串 - 部分安卓机型对 MTU 限制严格(默认 23 字节),大指令要分包,但摩拜类通常 ≤ 20 字节,先按单包试
- 写入后不立即有响应,需监听
uni.onBLECharacteristicValueChange等设备回传结果码,而不是依赖 write 的 success 回调
最容易被忽略的是:iOS 上 notify/read/write 必须在同一个 service 下连续操作,中间穿插其他设备的 service 查询会导致句柄失效;Android 则对连接状态更敏感,断连后重连必须重新走一遍服务→特征值→启用通知全流程。


















