uni.openBluetoothAdapter失败常见原因:模拟器不支持;iOS需配置manifest权限及NSBluetoothAlwaysUsageDescription;Android 12+需动态申请bluetoothScan/connect权限并处理定位权限;必须等待openAdapter成功后再调startDiscovery,且onBluetoothDeviceFound须提前注册; deviceId须严格使用回调返回值,格式校验防大小写错误;连接后需监听onBLEConnectionStateChange确认稳定再查服务与特征值。

uni-app App端调用uni.openBluetoothAdapter失败的常见原因
App端蓝牙功能在真机上才能运行,模拟器里调用uni.openBluetoothAdapter必失败,且不会报错,只会静默卡住或回调不触发。iOS 和 Android 行为还不一样:iOS 需提前在 manifest.json 里勾选「蓝牙」权限并填写 NSBluetoothAlwaysUsageDescription;Android 则必须动态申请 android.permission.BLUETOOTH_SCAN(Android 12+)和 android.permission.BLUETOOTH_CONNECT(Android 12+),老版本还需 android.permission.ACCESS_FINE_LOCATION——因为系统把蓝牙扫描归类为位置行为。
实操建议:
- 检查
manifest.json → app-plus → permissions是否已完整配置蓝牙相关权限项 - Android 12+ 必须调用
uni.authorize({scope: 'scope.bluetoothScan'})和uni.authorize({scope: 'scope.bluetoothConnect'}),不能只授权一次 - iOS 真机首次运行时,
uni.openBluetoothAdapter成功后才会弹出系统权限框,不是之前弹 - 调用前先
uni.getSystemInfoSync().platform === 'ios'分支处理,避免安卓逻辑误走 iOS 路径
搜索设备时uni.startBluetoothDevicesDiscovery没返回结果
最常被忽略的是:没等 uni.openBluetoothAdapter 完全 success 就直接 start discovery,或者 discovery 启动后没监听 uni.onBluetoothDeviceFound —— 这个监听必须在 start 前注册,且仅对本次 discovery 有效,重启就得重绑。
实操建议:
- 确保
uni.openBluetoothAdapter的 success 回调里再调uni.startBluetoothDevicesDiscovery -
uni.onBluetoothDeviceFound必须在 start 前注册,且不要用箭头函数(this 绑定问题会导致监听失效) - Android 下若仍无设备,尝试传参
{services: [], allowDuplicatesKey: true},某些设备广播时不带 service UUID,空 services 才能扫到 - iOS 对非标准广播包过滤更严,如果设备是自定义 BLE 协议,务必确认它广播了
0x1800(Generic Access)等基础 service
连接设备后uni.createBLEConnection报错errCode: 10005
errCode: 10005 是「连接超时」,不是设备不存在。根本原因是:调用 uni.createBLEConnection 时传入的 deviceId 不是 uni.onBluetoothDeviceFound 返回的那个,而是从列表里随便取的、或缓存旧值、或大小写混用(iOS 设备 ID 全大写,Android 可能小写)。
实操建议:
- 只信任
uni.onBluetoothDeviceFound回调里的device.deviceId,别用 name 或其他字段做 key - 连接前加一层校验:
if (!device.deviceId || !/^[0-9A-F]{2}(:[0-9A-F]{2}){5}$/i.test(device.deviceId))(粗略格式判断) - Android 12+ 上,连接前必须确保已调用过
uni.getConnectedBluetoothDevices并拿到设备,否则部分厂商系统会拦截 - 连接失败后别立刻重试,等 1.5s 以上再试,底层 stack 需要恢复时间
获取服务与特征值时uni.getBLEDeviceServices返回空数组
不是设备没服务,而是连接还没稳定。iOS 尤其明显:连接成功回调触发后,立刻查 services,大概率返回空。Android 好些,但也有概率。
实操建议:
- 必须监听
uni.onBLEConnectionStateChange,确认connected === true且state === 'connected'后再查服务 - 查服务前加
setTimeout(() => { uni.getBLEDeviceServices(...) }, 300),iOS 建议至少 300ms - 查到 services 后,再逐个调
uni.getBLEDeviceCharacteristics,别一次性并发请求多个 service - 某些设备只在特定 service 下暴露 characteristic,比如心率设备在
0x180D(Heart Rate)下才有0x2A37(Heart Rate Measurement),别硬扫所有 service
蓝牙交互链条长、平台差异大,最容易栽在「以为调用了就等于完成了」—— 比如 openAdapter 成功不等于权限已获,startDiscovery 开启不等于设备立刻出现,connect 成功不等于服务马上可读。每一步都要等对应事件回调落地,而不是靠 setTimeout 硬等。

















