问题描述:
最近用到小程序的蓝牙,设备通过安卓机测试以后以为没有问题了(没有苹果🥲🥲🥲!),后续发现在iPhone上不行。AI了一下,找到了答案,但是浪费了很多时间在小问题上。
在Android平台上,获取到的deviceId为设备的MAC地址;而在iOS平台上,获取到的deviceId为设备的UUID。
实现效果:
解决方案:
uni.getBluetoothDevices({
success(res) {
if (res.devices.length > 0) {
res.devices.forEach((v) => {
var val = v.localName || v.name;
if (val.indexOf("RF") == -1) return;
// 查找到名称包括RF的设备
// serviceData 是对象,需要把值取出来才能用Uint8Array转化
let serviceData = v.serviceData;
if (typeof serviceData === "object" && serviceData !== null) {
const serviceDataKeys = Object.keys(serviceData);
const serviceDataBuffer =
serviceDataKeys.length && serviceData[serviceDataKeys];
v.uuidObj = parseServiceData(serviceDataBuffer);
} else {
v.uuidObj = {};
}
});
}
},
});
function parseServiceData(buffer) {
// console.log("buffer====", buffer);
if (!(buffer instanceof ArrayBuffer)) return {};
const view = new Uint8Array(buffer);
if (buffer.byteLength === 14) {
return {
macAddress: Array.from(view.slice(0, 6))
.map((b) => b.toString(16).padStart(2, "0"))
.join(":")
.toUpperCase(),
major: (view[7] << 8) | view[6], // 0x0708 → 1800
minor: (view[9] << 8) | view[8], // 0x0506 → 1286
txPower: new Int8Array([view[10]])[0], // 0 → 0 dBm
advertisingInterval: (view[12] << 8) | view[11], // 0x03E8 → 1000 ms
batteryLevel: view[13], // 0x51 → 81%
};
} else if (buffer.byteLength === 6) {
return {
macAddress: Array.from(view.slice(0, 6))
.reverse()
.map((b) => b.toString(16).padStart(2, "0"))
.join(":")
.toUpperCase(),
};
}
}
关键问题:
- 确定厂商在蓝牙设备中配置了mac信息。蓝牙广播收到的蓝牙信息中的serviceData 和advertisData是什么?
字段 | 作用 | 包含关系 | 示例用途 |
---|---|---|---|
advertisData | 通用广播信息(设备名、厂商数据等) | 包含 serviceData 和其他字段 | 设备发现、基础信息传递 |
serviceData | 特定服务相关的数据 | 是 advertisData 的子集 | 心率数据、信标标识、传感器数据 |
- 确定advertisData/serviceData数据解析格式。看不懂就AI解释一下。
- 通过getBluetoothDevices获取到的蓝牙设备信息如图。advertisData是个ArrayBuffer类型。serviceData:是个ArrayBuffer类型的对象,key值是:00001803-0000-1000-8000-00805F9B34FB,因为mac信息在serviceData中,所以直接解析serviceData的值。serviceData是个对象,需要将value值(ArrayBuffer)取出来转Uint8Array。注意转化为Uint8Array后,其长度不变。比如原来长度,转化后也是14。
serviceData: Proxy(Object) {00001803-0000-1000-8000-00805F9B34FB: ArrayBuffer(14)}
。注意不同设备serviceData的字节长度不同,需要区别处理。
const serviceDataKeys = Object.keys(serviceData);
const serviceDataBuffer =serviceDataKeys.length && serviceData[serviceDataKeys];
v.uuidObj = parseServiceData(serviceDataBuffer);
ArrayBuffer是JavaScript中处理二进制数据的核心对象,它表示一段固定长度的原始二进制数据缓冲区。ArrayBuffer本身不能直接读写,必须通过TypedArray(如Uint8Array、Int16Array等)或DataView来操作数据。其核心特性包括固定长度、内存直接操作以及高效处理二进制数据。
- 一般mac占6个字节,取转化为Uint8Array后的数组对应位置的值转化为16进制后就能拿到mac值了。
macAddress: Array.from(view.slice(0, 6))
.map((b) => b.toString(16).padStart(2, "0"))
.join(":")
.toUpperCase()