uni-app中device.deviceId在Android上不稳定、iOS上为随机UUID,非真实MAC;稳定获取MAC唯一路径是解析广播包manufacturerData或serviceData字段;业务应放弃MAC,改用plus.device.uuid+设备名+广播数据交叉验证。

uni-app里device.deviceId不是MAC地址,iOS根本不会返回真实MAC
你在onBluetoothDeviceFound或onBLEConnectionStateChange里拿到的device.deviceId,在Android上可能是形如"11:22:33:44:55:66"的字符串,但这是不稳定的——系统权限、WiFi开关、蓝牙状态都会让它变成"00:00:00:00:00:00"或null;而在iOS上它永远是随机UUID(如"f1a2b3c4-d5e6-7890-g1h2-i3j4k5l6m7n8"),这是Core Bluetooth框架强制加密的结果,不是bug,是苹果的隐私沙盒策略。
真机上能稳定读到MAC的唯一路径:解析广播包里的manufacturerData或serviceData
设备厂商如果在BLE广播中主动把MAC嵌入manufacturerData或serviceData字段,你才能从device.advertisData里提取。这需要你清楚目标设备的广播协议:
-
advertisData是ArrayBuffer,必须先转成Uint8Array再按字节解析 - 常见位置:MAC常放在
manufacturerData的第2–7字节(小端/大端需确认),或serviceData某个固定UUID对应的value中 - 示例片段:
const arr = new Uint8Array(device.advertisData); // 假设MAC在manufacturerData起始偏移2字节处,共6字节 if (arr.length > 8 && arr[0] === 0x09) { // 0x09是manufacturerData类型标识 const macBytes = arr.slice(2, 8); const macStr = Array.from(macBytes).map(b => b.toString(16).padStart(2, '0')).join(':'); }
Android 10+和iOS都禁止直接读取wlan0 MAC,plus.networkinfo.getNetworkInfo完全没用
别试plus.networkinfo.getNetworkInfo()——它只返回网络类型和信号强度,根本不含MAC字段。想用Java反射或NetworkInterface.getByName("wlan0")?Android 10+默认启用MAC随机化,即使你有ACCESS_FINE_LOCATION和LOCAL_MAC_ADDRESS权限,用户也得手动去系统设置里开启“本地网络设备地址”;iOS则从底层就屏蔽了所有硬件地址API。这些限制在2026年依然有效,且无绕过方案。
业务上该怎么做:放弃MAC,改用设备指纹+广播数据绑定
如果你要做设备绑定、唯一识别或防多连,硬啃MAC只会反复踩坑。实际可行的组合是:
- 用
plus.device.uuid作为设备持久ID(Android/iOS均稳定) - 把
device.name或device.localName与广播中的固定前缀(比如"DRYER_112233445566")做字符串匹配 - 连接成功后,立刻读取设备公开的service characteristic(比如型号、固件版本),和服务端存的设备编码比对
- 对同一物理设备,不同手机扫出来的
deviceId必然不同,但name + advertisData内容 + uuid三者交叉验证,准确率接近100%
最易被忽略的一点:iOS每次重装App或重启蓝牙,deviceId就变一次,但advertisData只要设备没改广播逻辑,就始终一致——这个差异必须写进你的设备绑定流程,否则安卓绑完,iOS用户永远连不上。


















