具有128位UUID的startLeScan在本机Android BLE实现上不起作用

One*_*rld 34 android bluetooth-lowenergy gatt android-4.3-jelly-bean

我在Nexus 4上新推出的Android 4.3 BLE API上使用startLeScan(新UUID [] {MY_DESIRED_128_BIT_SERVICE_UUID},回调)时遇到问题.

回调就是没有被调用.我仍然可以在日志中看到传入的包:

08-02 15:48:57.985: I/bt-hci(1051): btu_ble_process_adv_pkt
08-02 15:48:58.636: I/bt-hci(1051): BLE HCI(id=62) event = 0x02)
Run Code Online (Sandbox Code Playgroud)

如果我不使用该参数来过滤UUID,它可以工作.我们使用制造商特定的128位UUID作为我们公司的设备.

现在,我们的设备提供的服务比我在阵列中提供的服务更多.但那应该不是问题.

有人面临同样的问题吗?有解决方案吗

编辑

有几个与扫描有关的问题,这个问题只讨论一个问题:如果您还有扫描问题,请先阅读此评论.还要记住,我的设备强加了16位和128位UUID.大多数人都使用BLE标准提供的16位UUID,如Heart rate或Speed and Cadence.

Har*_*per 39

@Navin的代码很好,但它包含原始16位Android代码的溢出错误.(如果任一字节大于127,则它变为负整数.)

这是一个修复该bug 添加128位支持的实现:

private List<UUID> parseUuids(byte[] advertisedData) {
     List<UUID> uuids = new ArrayList<UUID>();

     ByteBuffer buffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN);
     while (buffer.remaining() > 2) {
         byte length = buffer.get();
         if (length == 0) break;

         byte type = buffer.get();
         switch (type) {
             case 0x02: // Partial list of 16-bit UUIDs
             case 0x03: // Complete list of 16-bit UUIDs
                 while (length >= 2) {
                     uuids.add(UUID.fromString(String.format(
                             "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                     length -= 2;
                 }
                 break;

             case 0x06: // Partial list of 128-bit UUIDs
             case 0x07: // Complete list of 128-bit UUIDs
                 while (length >= 16) {
                     long lsb = buffer.getLong();
                     long msb = buffer.getLong();
                     uuids.add(new UUID(msb, lsb));
                     length -= 16;
                 }
                 break;

             default:
                 buffer.position(buffer.position() + length - 1);
                 break;
         }
     }

     return uuids;
 }
Run Code Online (Sandbox Code Playgroud)


小智 22

尝试从广告的128位UUID中检索/过滤设备:

private List<UUID> parseUUIDs(final byte[] advertisedData) {
    List<UUID> uuids = new ArrayList<UUID>();

    int offset = 0;
    while (offset < (advertisedData.length - 2)) {
        int len = advertisedData[offset++];
        if (len == 0)
            break;

        int type = advertisedData[offset++];
        switch (type) {
        case 0x02: // Partial list of 16-bit UUIDs
        case 0x03: // Complete list of 16-bit UUIDs
            while (len > 1) {
                int uuid16 = advertisedData[offset++];
                uuid16 += (advertisedData[offset++] << 8);
                len -= 2;
                uuids.add(UUID.fromString(String.format(
                        "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
            }
            break;
        case 0x06:// Partial list of 128-bit UUIDs
        case 0x07:// Complete list of 128-bit UUIDs
            // Loop through the advertised 128-bit UUID's.
            while (len >= 16) {
                try {
                    // Wrap the advertised bits and order them.
                    ByteBuffer buffer = ByteBuffer.wrap(advertisedData,
                            offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
                    long mostSignificantBit = buffer.getLong();
                    long leastSignificantBit = buffer.getLong();
                    uuids.add(new UUID(leastSignificantBit,
                            mostSignificantBit));
                } catch (IndexOutOfBoundsException e) {
                    // Defensive programming.
                    Log.e(LOG_TAG, e.toString());
                    continue;
                } finally {
                    // Move the offset to read the next uuid.
                    offset += 15;
                    len -= 16;
                }
            }
            break;
        default:
            offset += (len - 1);
            break;
        }
    }

    return uuids;
}
Run Code Online (Sandbox Code Playgroud)


One*_*rld 11

这是至少在Android 4.3 JWR66Y中报告的错误:

  • 过滤工作,如果我提供我的16位UUID
  • 如果我提供128位UUID或者我提供两个UUID,则过滤不会返回任何扫描结果

我的设置:我的设备在广告(1 16位和1 128位)上提供2 个UUID,在服务发现时提供4个UUID(1 128位和3 16位).

即使它得到修复,我也警告所有人不要使用Android提供的过滤器选项.为了向后兼容,因为它在使用Android 4.3的三星Galaxy S3上被破坏了


sa.*_*dow 6

虽然4.3似乎不支持128位UUID的过滤,但这些UUID可能存在于LeScanCallback返回的byte [] scanRecord中.

可能有一种正确的方法来解析这些数据,但如果您每次都可以通过查找要查找的UUID的偏移量来手动过滤结果,那么您将获得相同的数据.您可以通过将扫描数据打印到日志(作为十六进制字符串)并查找您感兴趣的UUID(它们可能会遵循0x06或0x07并将被反转)来完成此操作.找到偏移量后,设置基本过滤器应该不会太难.

下面是一个简单的示例,它通过单个UUID进行过滤(使用Apache Commons Lang for ArrayUtils和此处的字节到十六进制方法,但您可以在必要时替换自己的代码)

public static boolean hasMyService(byte[] scanRecord) {

    // UUID we want to filter by (without hyphens)
    final String myServiceID = "0000000000001000800000805F9B34FB";

    // The offset in the scan record. In my case the offset was 13; it will probably be different for you
    final int serviceOffset = 13; 

    try{

        // Get a 16-byte array of what may or may not be the service we're filtering for
        byte[] service = ArrayUtils.subarray(scanRecord, serviceOffset, serviceOffset + 16);

        // The bytes are probably in reverse order, so we need to fix that
        ArrayUtils.reverse(service);

        // Get the hex string
        String discoveredServiceID = bytesToHex(service);

        // Compare against our service
        return myServiceID.equals(discoveredServiceID);

    } catch (Exception e){
        return false;
    }

}
Run Code Online (Sandbox Code Playgroud)