BLE获得在广告包中编码的uuid

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BLE获得在广告包中编码的uuid相关的知识,希望对你有一定的参考价值。

我试图获得uUID的ble设备。我正在关注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);
   }

返回 - btif_gattc_upstreams_evt:事件4096

答案

如果你想获得UUID /任何其他数据,例如制造商数据在BLE Scan之后的scanRec []字节之外,首先需要了解那些广告数据包的数据格式。

来自Bluetooth.org:

理论太多了,想看一些代码片段?下面的这个函数将直接打印解析的原始数据字节。现在,您需要知道每种类型的代码,以了解哪些数据包引用了哪些信息。例如键入:0x09,表示BLE设备名称,类型: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;
    }

    // ...
}

在解析之后,这些数据字节会更有意义,您可以找出下一级解码。

另一答案

正如评论中所提到的,BLE设备并不真正具有特定的UUID(但对于所包含的服务而言,其实很多)。然而,诸如iBeacon的一些方案在广告包中的制造商特定数据记录中编码唯一标识符。

这是一个非常低效但概念上简单的方法,将整个scanRecord转换为十六进制字符串表示以进行调试打印:

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

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

另一答案

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

关于UUID(取决于您正在开发的API)的重要类是:

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

在阅读了这些类的文档之后,这是我编写的代码,用于获取正在扫描的任何设备的UUID:

//对于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;
}

对于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;
}

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

另一答案

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

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

另一答案

您可以使用标准的android BluetoothGattCharacteristic apis,如getFloatValue(int formatType,int offset),getIntValue(int formatType,int offset),getStringValue(int offset)..请参阅非常好的android开发者网站教程here

 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));
    }

以上是关于BLE获得在广告包中编码的uuid的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中配置ble广告以供ios检测

BLE 外设无广告

iBeacon,是不是可以获得 BLE 设备列表?

如何获取 BLE 广告数据 Swift 2

自定义蓝牙低功耗广告数据和扫描响应数据

BLE学习笔记BLE协议中的16位UUID和128位UUID有啥区别?