Android(Java)开发之从BLE广播包中解析UUID

本文旨在于解析出16位UUID,对于128位的UUID应该方法大同小异,没测试过的不贴出来


16bit UUID:

128位的UUID相当长,设备间为了识别数据的类型需要发送长达16字节的数据。为了提高传输效率,蓝牙技术联盟(SIG)定义了一个称为“UUID基数”的128位通用唯一识别码,结合一个较短的16位数使用。二者仍然遵循通用唯一识别码的分配规则,只不过在设备间传输常用的UUID时,只发送较短的16位版本,接收方收到后补上蓝牙UUID基数即可。

蓝牙UUID基数如下:

00000000 – 0000 – 1000 – 8000 – 008059B34FB

如要发送的16位UUID为0x2A01,完整的128的UUID便是:

00002A01 – 0000 – 1000 – 8000 – 008059B34FB

  • 非完整的 16 bit UUID 列表: TYPE = 0x02;
  • 完整的 16 bit UUID 列表: TYPE = 0x03;
  • 非完整的 32 bit UUID 列表: TYPE = 0x04;
  • 完整的 32 bit UUID 列表: TYPE = 0x05;
  • 非完整的 128 bit UUID 列表: TYPE = 0x06;
  • 完整的 128 bit UUID 列表: TYPE = 0x07;

如果需要其他位的UUID自己去试验,欢迎把实验结果告诉我,不扯太多,还是扯代码:

private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
               final ScanRecordUtil scanRecordUtil = ScanRecordUtil.parseFromBytes(scanRecord);
               Logger.e(TAG, "scanRecordUtil" + scanRecordUtil.getUuids16S());
              }
    };

这是我实验的扫描函数


接下来是ScanRecordUtil这个类,这个类主要用来处理广播包的数据

/**
 * 我只把我能用的写了出来,没用的我没看懂
 */
public class ScanRecordUtil {

    private static final String TAG = "---ScanRecordUtil";
    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
    private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
    // Flags of the advertising data.
    private final int mAdvertiseFlags;
    // Transmission power level(in dB).
    private final int mTxPowerLevel;
    // Local name of the Bluetooth LE device.
    private final String mDeviceName;
    //Raw bytes of scan record.
    private final byte[] mBytes;
    private List mUuids16S;             //16位UUID,之前有其他的UUID占着名称我就取的这名称

    /**
     * Returns the advertising flags indicating the discoverable mode and capability of the device. * Returns -1 if the flag field is not set.
     */
    public int getAdvertiseFlags() {
        return mAdvertiseFlags;
    }

    /**
     * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE} * if the field is not set. This value can be used to calculate the path loss of a received * packet using the following equation: * 

* pathloss = txPowerLevel - rssi */ public int getTxPowerLevel() { return mTxPowerLevel; } /** * Returns the local name of the BLE device. The is a UTF-8 encoded string. * 拿到设备的名称 */ @Nullable public String getDeviceName() { return mDeviceName; } /** * Returns raw bytes of scan record. */ public byte[] getBytes() { return mBytes; } private ScanRecordUtil( List mUuids16S, int advertiseFlags, int txPowerLevel, String localName, byte[] bytes) { mDeviceName = localName; mAdvertiseFlags = advertiseFlags; mTxPowerLevel = txPowerLevel; mBytes = bytes; this.mUuids16S = mUuids16S; } /** * 获取16位UUID * @return */ public List getUuids16S() { return mUuids16S; } /** * 得到ScanRecordUtil 对象,主要逻辑 * @param scanRecord * @return */ public static ScanRecordUtil parseFromBytes(byte[] scanRecord) { if (scanRecord == null) { return null; } int currentPos = 0; int advertiseFlag = -1; List uuids16 = new ArrayList<>(); String localName = null; int txPowerLevel = Integer.MIN_VALUE; try { while (currentPos < scanRecord.length) { // length is unsigned int. int length = scanRecord[currentPos++] & 0xFF; if (length == 0) { break; } // / Note the length includes the length of the field type itself. int dataLength = length - 1; // fieldType is unsigned int. // 获取广播AD type int fieldType = scanRecord[currentPos++] & 0xFF; switch (fieldType) { case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE: parseServiceUuid16(scanRecord, currentPos, dataLength, uuids16); break; case DATA_TYPE_LOCAL_NAME_COMPLETE: localName = new String(extractBytes(scanRecord, currentPos, dataLength)); break; default: break; } currentPos += dataLength; } if (uuids_16.isEmpty()){ uuids_16 = null; } return new ScanRecordUtil(uuids16, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); // As the record is invalid, ignore all the parsed results for this packet // and return an empty record with raw scanRecord bytes in results return new ScanRecordUtil( null, -1, Integer.MIN_VALUE, null, scanRecord); } } /** * byte数组转16进制 * @param bytes * @return */ public static String bytesToHexFun3(byte[] bytes) { StringBuilder buf = new StringBuilder(bytes.length * 2); for (byte b : bytes) { // 使用String的format方法进行转换 buf.append(String.format("%02x", new Integer(b & 0xff))); } return buf.toString(); } // 16位UUID private static int parseServiceUuid16(byte[] scanRecord, int currentPos, int dataLength, List serviceUuids) { while (dataLength > 0) { byte[] uuidBytes = extractBytes(scanRecord, currentPos, dataLength); final byte[] bytes = new byte[uuidBytes.length]; Logger.e(TAG, "dataLength==uuidBytes.length" + (dataLength == uuidBytes.length)); for (int i = 0; i < uuidBytes.length; i++) { bytes[i] = uuidBytes[uuidBytes.length - 1 - i]; } serviceUuids.add(bytesToHexFun3(bytes)); dataLength -= dataLength; currentPos += dataLength; } return currentPos; } // Helper method to extract bytes from byte array. //b帮助我们解析byte数组 private static byte[] extractBytes(byte[] scanRecord, int start, int length) { byte[] bytes = new byte[length]; System.arraycopy(scanRecord, start, bytes, 0, length); return bytes; } }

 
  
用这些代码就能得到16位的UUID,这是我的项目里面的东西,对于你们能不能用我就不清楚了,既然我用了网上的资源解决了自己的问题,
我也要把我的知识贡献出来,开源才能使社会发展更快!

你可能感兴趣的:(android,ble,ble,scanRecode,广播包,uuid)