背景
个人开发过一种BLE设备有这样一种需求:当设备处于状态A时,广播设备名称A;处于状态B时,广播设备名称B。
问题
我们发现,当Android在进行Ble扫描的时候,扫描回调函数onScanResult中获取的设备名称并未随设备实时改变。
但是当使用nrfConnect进行扫描时,却发现设备广播名称确实是实时改变的。
原因
我们使用如下代码获取BLE设备名称,然而此时device.getName()中的名称是系统缓存的数据,而非实时的广播数据,要想获取实时的设备名称,必须自行解码实时广播数据。
1 private ScanCallback mScanCallback = new ScanCallback() { 2 @Override 3 public void onScanResult(int callbackType, ScanResult result) { 4 5 BluetoothDevice device = result.getDevice(); 6 if(null != device && null != device.getName()) { 7 Log.d("test", device.getName()); // not the real name 8 } 9 } 10 11 12 @Override 13 public void onScanFailed(int errorCode) { 14 super.onScanFailed(errorCode); 15 } 16 17 };
解决
通过分析BLE广播包协议,自行解码出设备名称。
1 private ScanCallback mScanCallback = new ScanCallback() { 2 @Override 3 public void onScanResult(int callbackType, ScanResult result) { 4 5 BluetoothDevice device = result.getDevice(); 6 if(null != device && null != device.getScanRecord().getBytes()) { 7 byte[] scanRecord = device.getScanRecord().getBytes(); // advertised data 8 String realName = parseDeviceName(scanRecord); 9 } 10 } 11 12 13 @Override 14 public void onScanFailed(int errorCode) { 15 super.onScanFailed(errorCode); 16 } 17 18 };
1 // return name String(successful) or null(failed) 2 public static String parseDeviceName(byte[] scanRecord) { 3 String ret = null; 4 if(null == scanRecord) { 5 return ret; 6 } 7 8 ByteBuffer buffer = ByteBuffer.wrap(scanRecord).order(ByteOrder.LITTLE_ENDIAN); 9 while (buffer.remaining() > 2) { 10 byte length = buffer.get(); 11 if (length == 0) 12 break; 13 14 byte type = buffer.get(); 15 length -= 1; 16 switch (type) { 17 case 0x01: // Flags 18 buffer.get(); // flags 19 length--; 20 break; 21 case 0x02: // Partial list of 16-bit UUIDs 22 case 0x03: // Complete list of 16-bit UUIDs 23 case 0x14: // List of 16-bit Service Solicitation UUIDs 24 while (length >= 2) { 25 buffer.getShort(); 26 length -= 2; 27 } 28 break; 29 case 0x04: // Partial list of 32 bit service UUIDs 30 case 0x05: // Complete list of 32 bit service UUIDs 31 while (length >= 4) { 32 buffer.getInt(); 33 length -= 4; 34 } 35 break; 36 case 0x06: // Partial list of 128-bit UUIDs 37 case 0x07: // Complete list of 128-bit UUIDs 38 case 0x15: // List of 128-bit Service Solicitation UUIDs 39 while (length >= 16) { 40 long lsb = buffer.getLong(); 41 long msb = buffer.getLong(); 42 length -= 16; 43 } 44 break; 45 case 0x08: // Short local device name 46 case 0x09: // Complete local device name 47 byte sb[] = new byte[length]; 48 buffer.get(sb, 0, length); 49 length = 0; 50 ret = new String(sb).trim(); 51 return ret; 52 case (byte) 0xFF: // Manufacturer Specific Data 53 buffer.getShort(); 54 length -= 2; 55 break; 56 default: // skip 57 break; 58 } 59 if (length > 0) { 60 buffer.position(buffer.position() + length); 61 } 62 } 63 return ret; 64 }
参考资料:
https://www.race604.com/ble-advertising/