1. 程式人生 > >雜記:解決Android掃描BLE裝置名稱不重新整理問題

雜記:解決Android掃描BLE裝置名稱不重新整理問題

背景

個人開發過一種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     }
View Code

 

 

 

參考資料:

https://www.race604.com/ble-advertising/