Android BLE 获取广告包中编码的 uuid

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22016224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:25:46  来源:igfitidea点击:

BLE obtain uuid encoded in advertising packet

androidbluetooth

提问by Boris Pawlowski

Im trying to get UUID of ble device. I was following android developers guide and so far I can get only device name and rssi. Im trying to get Uuid of the device that comes to scanning method that looks like this:

我正在尝试获取 ble 设备的 UUID。我正在关注 android 开发人员指南,到目前为止我只能获得设备名称和 rssi。我试图获取扫描方法的设备的 Uuid,如下所示:

    public void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {

        ParcelUuid[] myUUid =device.getUuids();
        for(ParcelUuid a :myUUid){
            Log.d("UUID",a.getUuid().toString());
        }
        String s = new String(scanRecord);
        int len = scanRecord.length;
        String scanRecords =new String(scanRecord) ;



        deviceMap.put(device.getName().toString(), rssi);
        Message msg = MainActivity.myHandler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putCharSequence("dev_name", device.getName().toString());
        bundle.putCharSequence("rssi", Integer.toString(rssi));
        msg.setData(bundle);
        MainActivity.myHandler.sendMessage(msg);
   }

this returns - btif_gattc_upstreams_evt: Event 4096

这将返回 - btif_gattc_upstreams_evt:事件 4096

回答by Khulja Sim Sim

If you want to get UUID / any other data e.g. Manufacturer Data out of scanRec[] bytes after BLE Scan, you first need to understand the data format of those Advertisement Data packet.

如果您想在 BLE 扫描后从 scanRec[] 字节中获取 UUID/任何其他数据,例如制造商数据,您首先需要了解这些广告数据包的数据格式。

Came from Bluetooth.org: Advertising or Scan Response Data format

来自 Bluetooth.org: 广告或扫描响应数据格式

Too much theory, want to see some code snippet? This function below would straight forward print parsed raw data bytes. Now, you need to know each type code to know what data packet refers to what information. e.g. Type : 0x09, refers to BLE Device Name, Type : 0x07, refers to UUID.

理论太多,想看一些代码片段吗?下面的这个函数将直接打印解析的原始数据字节。现在,您需要知道每个类型的代码才能知道什么数据包指的是什么信息。例如 Type : 0x09, 指的是 BLE Device Name, Type : 0x07, 指的是 UUID。

public void printScanRecord (byte[] scanRecord) {

    // Simply print all raw bytes   
    try {
        String decodedRecord = new String(scanRecord,"UTF-8");
        Log.d("DEBUG","decoded String : " + ByteArrayToString(scanRecord));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    // Parse data bytes into individual records
    List<AdRecord> records = AdRecord.parseScanRecord(scanRecord);


    // Print individual records 
    if (records.size() == 0) {
        Log.i("DEBUG", "Scan Record Empty");
    } else {
        Log.i("DEBUG", "Scan Record: " + TextUtils.join(",", records));
    }

}


public static String ByteArrayToString(byte[] ba)
{
  StringBuilder hex = new StringBuilder(ba.length * 2);
  for (byte b : ba)
    hex.append(b + " ");

  return hex.toString();
}


public static class AdRecord {

    public AdRecord(int length, int type, byte[] data) {
        String decodedRecord = "";
        try {
            decodedRecord = new String(data,"UTF-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        Log.d("DEBUG", "Length: " + length + " Type : " + type + " Data : " + ByteArrayToString(data));         
    }

    // ...

    public static List<AdRecord> parseScanRecord(byte[] scanRecord) {
        List<AdRecord> records = new ArrayList<AdRecord>();

        int index = 0;
        while (index < scanRecord.length) {
            int length = scanRecord[index++];
            //Done once we run out of records
            if (length == 0) break;

            int type = scanRecord[index];
            //Done if our record isn't a valid type
            if (type == 0) break;

            byte[] data = Arrays.copyOfRange(scanRecord, index+1, index+length);

            records.add(new AdRecord(length, type, data));
            //Advance
            index += length;
        }

        return records;
    }

    // ...
}

After this parsing, those data bytes would make more sense, and you can figure out next level of decoding.

经过这个解析,那些数据字节会更有意义,你可以找出下一级的解码。

回答by Chris Stratton

As mentioned in comments, a BLE device doesn't really have a specific UUID (but rather many for included services). However, some schemes such as iBeacon encode a unique identifier in a manufacturer-specific data record in an advertising packet.

正如评论中所提到的,BLE 设备实际上并没有特定的 UUID(而是包含许多服务)。但是,一些方案(例如 iBeacon)在广告数据包中的制造商特定数据记录中编码唯一标识符。

Here's a quite inefficient but conceptually simple way to convert the entire scanRecord to a hex string representation for debug printing:

这是将整个 scanRecord 转换为用于调试打印的十六进制字符串表示的一种效率很低但概念上很简单的方法:

String msg = "payload = ";
for (byte b : scanRecord)
  msg += String.format("%02x ", b);

Note that this will include both the actual advertising packet and a number of meaningless trailing bytes, which should be ignored after parsing the structure (length field) contained in the advertising packet itself.

请注意,这将包括实际的广告数据包和许多无意义的尾随字节,在解析广告数据包本身包含的结构(长度字段)后应忽略这些字节。

回答by ADEBAYO OSIPITAN

I had this same issue while developing my ble app, but after reading documentation on the following link: https://developer.android.com/reference/android/bluetooth/le/ScanResult.html

我在开发 ble 应用程序时遇到了同样的问题,但在阅读以下链接上的文档后:https: //developer.android.com/reference/android/bluetooth/le/ScanResult.html

the important classes as far as UUID (Depending on the API you are developing for) is concerned are:

就 UUID(取决于您正在开发的 API)而言,重要的类是:

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

after reading through documentation for these classes, this is the code I wrote to get UUID for any device being scanned:

通读这些类的文档后,这是我编写的代码,用于获取任何被扫描设备的 UUID:

//For API < 21:

//对于 API < 21:

private BluetoothAdapter.LeScanCallback scanCallBackLe =
        new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
                final int RSSI = rssi;
                if (RSSI >= signalThreshold){
                    scanHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            AdvertiseData data = new AdvertiseData.Builder()
                                    .addServiceUuid(ParcelUuid
                                            .fromString(UUID
                                                    .nameUUIDFromBytes(scanRecord).toString())).build();
                            scannerActivity.addDevice(device, RSSI, getUUID(data));
                        }
                    });
                }
            }
        };

//For APIs less than 21, Returns Device UUID
public String getUUID(AdvertiseData data){
    List<ParcelUuid> UUIDs = data.getServiceUuids();
    //ToastMakers.message(scannerActivity.getApplicationContext(), UUIDs.toString());
    String UUIDx = UUIDs.get(0).getUuid().toString();
    Log.e("UUID", " as list ->" + UUIDx);
    return UUIDx;
}

For API's > 21:

对于 API > 21:

private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, final ScanResult result) {
        Log.i("callbackType", String.valueOf(callbackType));
        Log.i("result", result.toString());
        final int RSSI = result.getRssi();
        if (RSSI>=signalThreshold) {
            scanHandler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            BluetoothDevice device = result.getDevice();
                            scannerActivity.addDevice(device, result.getRssi(), getUUID(result));
                        }
                    });
        }
    } ...}

//For APIs greater than 21, Returns Device UUID
public String getUUID(ScanResult result){
    String UUIDx = UUID
            .nameUUIDFromBytes(result.getScanRecord().getBytes()).toString();
    ToastMakers.message(scannerActivity.getApplicationContext(), UUIDx);
    Log.e("UUID", " as String ->>" + UUIDx);
    return UUIDx;
}

I was able to obtain a 128 bit UUID of any device using this code. :)

我能够使用此代码获得任何设备的 128 位 UUID。:)

回答by Andrew

I found a java library to parse the advertising packet

我找到了一个java库来解析广告包

https://github.com/TakahikoKawasaki/nv-bluetooth

https://github.com/TakahikoKawasaki/nv-bluetooth

回答by rupesh jain

You can use standard android BluetoothGattCharacteristicapis like getFloatValue(int formatType, int offset), getIntValue(int formatType, int offset), getStringValue(int offset)..refer very nice android developer site tutorial here

您可以使用标准的 android BluetoothGattCharacteristicapi,如getFloatValue(int formatType, int offset)、getIntValue(int formatType, int offset)、getStringValue(int offset)..在此处参考非常好的 android 开发者网站教程

 if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
        int flag = characteristic.getProperties();
        int format = -1;
        if ((flag & 0x01) != 0) {
            format = BluetoothGattCharacteristic.FORMAT_UINT16;
            Log.d(TAG, "Heart rate format UINT16.");
        } else {
            format = BluetoothGattCharacteristic.FORMAT_UINT8;
            Log.d(TAG, "Heart rate format UINT8.");
        }
        final int heartRate = characteristic.getIntValue(format, 1);
        Log.d(TAG, "Received heart rate: " + heartRate);
        intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
    }