uni-app 实现连接蓝牙功能
目前我用的是微信小程序实现无需额外配置,app的需要额外在 manifest.json 文件添加配置。

一、初始化蓝牙模块
注意
- 其他蓝牙相关 API 必须在
uni.openBluetoothAdapter调用之后使用。否则 API 会返回错误(errCode=10000)。 - 在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下,调用
uni.openBluetoothAdapter会返回错误(errCode=10001),3. 表示手机蓝牙功能不可用。此时APP蓝牙模块已经初始化完成,可通过uni.onBluetoothAdapterStateChange监听手机蓝牙状态的改变,也可以调用蓝牙模块的所有API。
{
"errMsg": "openBluetoothAdapter:ok"
}
二、获取本机蓝牙适配器状态
文档:uni.getBluetoothAdapterState
三、开始搜寻附近的蓝牙外围设备
文档:uni.startBluetoothDevicesDiscovery
开始搜寻附近的蓝牙外围设备。此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。
{
"errMsg": "startBluetoothDevicesDiscovery:ok"
}
注意:
App 端目前仅支持发现ble蓝牙设备,更多蓝牙设备发现,可以使用 Native.js,参考:https://ask.dcloud.net.cn/article/114。 也可以在插件市场获取原生插件
四、监听寻找到新设备的事件
获取蓝牙设备列表,找到需要的那个,设备列表在回调函数中
{
"devices": [
{
"deviceId": "D2:5D:88:48:54:85",
"name": "",
"RSSI": -85,
"localName": "",
"advertisServiceUUIDs": [],
"advertisData": {}
}
]
}
注意
若在 uni.onBluetoothDeviceFound 回调了某个设备,则此设备会添加到 uni.getBluetoothDevices 接口获取到的数组中。
五、连接低功耗蓝牙设备
若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
注意
请保证尽量成对的调用 createBLEConnection 和 closeBLEConnection 接口。安卓如果多次调用 createBLEConnection 创建连接,有可能导致系统持有同一设备多个连接的实例,导致调用 closeBLEConnection 的时候并不能真正的断开与设备的连接。
蓝牙连接随时可能断开,建议监听 uni.onBLEConnectionStateChange 回调事件,当蓝牙设备断开时按需执行重连操作
若对未连接的设备或已断开连接的设备调用数据读写操作的接口,会返回 10006 错误,建议进行重连操作。
{
"errMsg": "createBLEConnection:ok"
}
六、获取蓝牙设备所有服务(service)
{
"services": [
{
"uuid": "00001800-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "00001801-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "0000180A-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "D0611E78-BBB4-4591-A5F8-487910AE4366",
"isPrimary": true
},
{
"uuid": "9FA480E0-4967-4542-9390-D343DC5D04AE",
"isPrimary": true
},
{
"uuid": "0000FFF1-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "BAF550E1-8B33-4A03-A6DC-3E2153FD242B",
"isPrimary": true
},
{
"uuid": "0000180F-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "00001805-0000-1000-8000-00805F9B34FB",
"isPrimary": true
},
{
"uuid": "7905F431-B5CE-4E99-A40F-4B1E122D00D0",
"isPrimary": true
},
{
"uuid": "89D3502B-0F36-433A-8EF4-C502AD55F8DC",
"isPrimary": true
}
],
"errMsg": "getBLEDeviceServices:ok"
}
七、获取蓝牙设备某个服务中所有特征值
文档:uni.getBLEDeviceCharacteristics
{
"characteristics": [
{
"uuid": "0000FFF1-0000-1000-8000-00805F9B34FB",
"properties": {
"read": true,
"write": true,
"notify": true,
"indicate": true
}
}
],
"errMsg": "getBLEDeviceCharacteristics:ok"
}
八、启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值
文档:uni.notifyBLECharacteristicValueChange
启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。注意:必须设备的特征值支持 notify 或者 indicate 才可以成功调用。 另外,必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件
九、向低功耗蓝牙设备特征值中写入二进制数据
文档:uni.writeBLECharacteristicValue
向低功耗蓝牙设备特征值中写入二进制数据。注意:必须设备的特征值支持 write 才可以成功调用。
注意
- 并行调用多次会存在写失败的可能性。
- APP不会对写入数据包大小做限制,但系统与蓝牙设备会限制蓝牙4.0单次传输的数据大小,超过最大字节数后会发生写入错误,建议每次写入不超过20字节。
- 若单次写入数据过长,iOS 上存在系统不会有任何回调的情况(包括错误回调)。
- 安卓平台上,在调用
notifyBLECharacteristicValueChange成功后立即调用writeBLECharacteristicValue接口,在部分机型上会发生 10008 系统错误
{
"errMsg": "writeBLECharacteristicValue:ok"
}
十、监听低功耗蓝牙设备的特征值变化事件
文档:uni.onBLECharacteristicValueChange
监听低功耗蓝牙设备的特征值变化事件。必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification
进制转换小工具
// json对象转二进制
const encodeStr = (s) => {
if (typeof TextEncoder !== 'undefined') return new TextEncoder().encode(s);
const out = [];
for (const ch of s || '') {
const cp = ch.codePointAt(0);
if (cp <= 0x7F) out.push(cp);
else if (cp <= 0x7FF) out.push(0xC0 | (cp >> 6), 0x80 | (cp & 0x3F));
else if (cp <= 0xFFFF) out.push(0xE0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3F), 0x80 | (
cp & 0x3F));
else out.push(0xF0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3F), 0x80 | ((cp >> 6) & 0x3F),
0x80 | (cp & 0x3F));
}
return new Uint8Array(out);
};
const toArrayBufferJson = (obj) => {
const u8 = encodeStr(JSON.stringify(obj));
return (u8.byteOffset === 0 && u8.byteLength === u8.buffer.byteLength) ? u8.buffer : u8
.slice().buffer;
};
// 二进制 -> JSON 对象
const bufferToUtf8 = (buffer) => {
if (!buffer) return ''
// 确保是 Uint8Array
let uint8Array = buffer instanceof Uint8Array
? buffer
: new Uint8Array(buffer)
// H5 / 新版 App 支持
if (typeof TextDecoder !== 'undefined') {
try {
return new TextDecoder('utf-8').decode(uint8Array)
} catch (e) {
// 继续走兜底
}
}
// 兜底方案:手写 UTF-8 解码(兼容微信小程序)
let out = ''
let i = 0
const len = uint8Array.length
while (i < len) {
const c = uint8Array[i++]
if (c < 0x80) {
out += String.fromCharCode(c)
} else if (c < 0xE0) {
const c2 = uint8Array[i++]
out += String.fromCharCode(
((c & 0x1F) << 6) | (c2 & 0x3F)
)
} else if (c < 0xF0) {
const c2 = uint8Array[i++]
const c3 = uint8Array[i++]
out += String.fromCharCode(
((c & 0x0F) << 12) |
((c2 & 0x3F) << 6) |
(c3 & 0x3F)
)
} else {
// 4 字节 UTF-8(emoji)
const c2 = uint8Array[i++]
const c3 = uint8Array[i++]
const c4 = uint8Array[i++]
let codePoint =
((c & 0x07) << 18) |
((c2 & 0x3F) << 12) |
((c3 & 0x3F) << 6) |
(c4 & 0x3F)
codePoint -= 0x10000
out += String.fromCharCode(
0xD800 + (codePoint >> 10),
0xDC00 + (codePoint & 0x3FF)
)
}
}
return out
}

浙公网安备 33010602011771号