解決uniapp實現ios系統中低功耗藍牙通訊失敗問題
?? UniApp 實現 App 連接低功耗藍牙(BLE)通訊
手頭上有一個 uniapp 實現低功耗藍牙通訊設備的項目,本來 Android 版本沒問題已經上線,到了發布測試 iOS 出問題了,連接上了設備但是通訊失敗,排查了下才發現是協議通訊中有包含六位 ID,也就是設備的 MAC 地址,因為設備主要標識符通常是設備 MAC,Android 能直接獲取,但是喵的 iOS 不給,所以最終只能找硬件工程師進行協商找解決方案。
一、BLE 通訊協議說明(這是本項目協議消息體構成)
客戶端發送消息體格式:
1Byte(功能ID) + 6Byte(設備ID) + 1Byte(版本號) + nByte(功能內容)
服務端回應消息體格式:
1Byte(功能ID) + nByte(功能內容)
?? 二、Android 與 iOS 的差異與解決方案
?? Android
deviceId返回即為設備 Mac 地址,可直接進行數據通訊。
?? iOS
deviceId返回的是一個 UUID,并非真實 Mac 地址。
?? UUID 是如何生成的?
- iOS 使用
CBPeripheral.identifier生成一個臨時 UUID。 - 此 UUID 是 iOS 系統基于 BLE 發現過程為每個設備 隨機生成的唯一標識符。
- 與設備的真實物理地址無關,每次藍牙重連或重新發現設備時可能會改變。
- Apple 這么設計是為 保護用戶隱私,避免開發者追蹤設備或用戶。
解決方案:
方法一:連接成功后監聽設備主動返回 Mac 地址
- 設備會在連接 1 秒后主動發送 Mac 地址。
- 若無回應,設備會每 2 秒重發一次,直到收到。
uni.onBLECharacteristicValueChange((res) => {
const value = ab2hex(res.value);
if (value.startsWith("01")) {
const mac = value.slice(2, 14); // 截取6字節mac
uni.setStorageSync('deviceMac', mac) // 存儲mac用于后續通訊,有用 vuex 或者 pinia 等其他方法也可以
await this.send('11'); // 應答設備防止一直上報
}
});
方法二:通過廣播數據 (advertisData) 提取 Mac 地址
- 每次掃描設備時,廣播包中可能包含 Mac 地址字段。
- 若存在隱私顧慮,可對其 加密處理,連接設備前進行 解密并緩存。
import CryptoJS from "crypto-js";
function decryptMac(cipherHex) {
const key = CryptoJS.enc.Hex.parse("00112233445566778899aabbccddeeff"); // 16字節密鑰
const iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000"); // 默認全0 IV
const encrypted = CryptoJS.enc.Hex.parse(cipherHex);
const encryptedBase64 = CryptoJS.enc.Base64.stringify(encrypted);
const decrypted = CryptoJS.AES.decrypt(encryptedBase64, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return decrypted.toString(CryptoJS.enc.Hex);
}
uni.startBluetoothDevicesDiscovery({
success() {
uni.onBluetoothDeviceFound((device) => {
const advertisData = device.advertisData;
const raw = ab2hex(advertisData);
const encryptedMac = raw.slice(10, 42); // 示例中為16字節加密
const mac = decryptMac(encryptedMac);
console.log("解密出的Mac地址:", mac);
});
},
});
三、通訊流程簡單示意
async function connectBLE(device) {
await uni.createBLEConnection({ deviceId: device.deviceId });
// 監聽特征值變化
uni.onBLECharacteristicValueChange((res) => handleResponse(res));
// 啟用 notify 監聽
await uni.notifyBLECharacteristicValueChange({
deviceId: device.deviceId,
serviceId: serviceUUID,
characteristicId: notifyUUID,
state: true,
});
// 發送數據
const platform = uni.getSystemInfoSync().platform;
const macAddress = uni.getStorageSync("deviceMac");
const payload = buildPayload(
"01",
platform == "ios" ? macAddress : device.deviceId,
"01",
content
);
await uni.writeBLECharacteristicValue({
deviceId: device.deviceId,
serviceId: serviceUUID,
characteristicId: writeUUID,
value: str2ab(payload),
});
}
??? 四、安全建議
- 廣播中的 Mac 地址應加密,防止泄露。
- 通訊內容建議使用 AES 加密,提升安全等級。
- 使用 CRC16 或 hash 校驗數據完整性。
?? 五、總結
| 項目 | Android | iOS |
|---|---|---|
| deviceId | 返回真實 Mac 地址 ? | 返回 UUID,需特殊處理 ?? |
| 獲取 Mac | 可直接使用 | 連接后監聽 / 廣播包解析 |
| 廣播數據 | 可用,可加密攜帶 Mac 地址 | 推薦使用,用于連接前標識設備 |
| 加密建議 | AES 對稱加密 / CRC16 校驗 | 同 Android,建議一致處理方式 |

浙公網安備 33010602011771號