You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于RxAndroidBle实现扫描指定UUID的iBeacon并获取广播数据

如何使用RxAndroidBle扫描特定UUID的iBeacon?

我在Android平台使用RxAndroidBle库进行蓝牙扫描,现有扫描方法无法识别我的iBeacon(仓库已说明原因),但我不清楚如何修改方法来扫描我的iBeacon。

原扫描方法:

public static void startScanning() { 
    if (isScanning()) { 
        return; 
    } 
    final BluetoothClient instance = getInstance(); 
    Log.d(TAG, "Starting to scan for beacons"); 
    ScanSettings scanSettings = new ScanSettings.Builder() 
        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 
        .build(); 
    instance.scanningSubscription = instance.rxBleClient.scanBleDevices(scanSettings) 
        .subscribe(new Observer<ScanResult>() { 
            @Override 
            public void onCompleted() { } 
            @Override 
            public void onError(Throwable e) { 
                Log.e(TAG, "Bluetooth scanning error", e); 
            } 
            @Override 
            public void onNext(ScanResult scanResult) { 
                instance.processScanResult(scanResult); 
            } 
        }); 
}

我尝试添加ScanFilter来匹配iBeacon的UUID,但这个实现无效,无法过滤出目标设备:

ScanSettings scanSettings = new ScanSettings.Builder() 
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
    .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 
    .build(); 
ScanFilter scanFilter = new ScanFilter.Builder() 
    .setServiceUuid(UUID).build(); 
instance.scanningSubscription = instance.rxBleClient.scanBleDevices(scanSettings, scanFilter) 
    .subscribe(new Observer<ScanResult>() { 
        @Override 
        public void onCompleted() { } 
        @Override 
        public void onError(Throwable e) { 
            Log.e(TAG, "Bluetooth scanning error", e); 
        } 
        @Override 
        public void onNext(ScanResult scanResult) { 
            instance.processScanResult(scanResult); 
        } 
    });

我家中的4个iBeacon UUID均为EBEFD083-70A2-47C8-9837-E7B5634DF524,请问如何修改该方法以正确扫描此特定UUID的iBeacon,或者如何封装iBeacon API以获取仓库预期的必要广播数据?


问题根源

你用setServiceUuid()来过滤iBeacon是行不通的——因为iBeacon的广播并不是基于GATT服务UUID的,它是苹果定义的一种制造商特定广播数据格式,使用的是苹果的公司ID(0x004C),所以系统的ScanFilter无法通过服务UUID直接匹配iBeacon。

解决方案:两种可行的扫描方式

方式1:先扫描所有设备,再在回调中过滤iBeacon

这种方式不需要修改扫描设置,而是在onNext()中解析扫描结果的广播数据,判断是否是目标UUID的iBeacon:

public static void startScanning() { 
    if (isScanning()) { 
        return; 
    } 
    final BluetoothClient instance = getInstance(); 
    final UUID TARGET_IBeACON_UUID = UUID.fromString("EBEFD083-70A2-47C8-9837-E7B5634DF524");
    Log.d(TAG, "Starting to scan for beacons"); 
    ScanSettings scanSettings = new ScanSettings.Builder() 
        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 
        .build(); 

    instance.scanningSubscription = instance.rxBleClient.scanBleDevices(scanSettings) 
        .subscribe(new Observer<ScanResult>() { 
            @Override 
            public void onCompleted() { } 
            @Override 
            public void onError(Throwable e) { 
                Log.e(TAG, "Bluetooth scanning error", e); 
            } 
            @Override 
            public void onNext(ScanResult scanResult) { 
                // 解析广播数据,判断是否是目标iBeacon
                if (isTargetIBeacon(scanResult, TARGET_IBeACON_UUID)) {
                    instance.processScanResult(scanResult);
                }
            } 
        }); 
}

// 解析iBeacon广播数据的工具方法
private static boolean isTargetIBeacon(ScanResult scanResult, UUID targetUuid) {
    BluetoothDevice device = scanResult.getDevice();
    ScanRecord scanRecord = scanResult.getScanRecord();
    if (scanRecord == null) return false;

    byte[] manufacturerData = scanRecord.getManufacturerSpecificData(0x004C); // 苹果公司ID
    if (manufacturerData == null || manufacturerData.length < 25) return false; // iBeacon数据至少25字节

    // 验证iBeacon的类型(前2字节是0x0215)
    if (manufacturerData[0] != 0x02 || manufacturerData[1] != 0x15) return false;

    // 提取UUID部分(字节2-17)
    byte[] uuidBytes = Arrays.copyOfRange(manufacturerData, 2, 18);
    UUID beaconUuid = uuidBytesToUuid(uuidBytes);

    return beaconUuid.equals(targetUuid);
}

// 将字节数组转换为UUID的工具方法
private static UUID uuidBytesToUuid(byte[] bytes) {
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    long high = bb.getLong();
    long low = bb.getLong();
    return new UUID(high, low);
}

方式2:使用制造商数据的ScanFilter(API 21+)

如果你的最低API版本是21及以上,可以直接构建匹配苹果制造商数据和目标UUID的ScanFilter,减少不必要的回调:

public static void startScanning() { 
    if (isScanning()) { 
        return; 
    } 
    final BluetoothClient instance = getInstance(); 
    UUID targetUuid = UUID.fromString("EBEFD083-70A2-47C8-9837-E7B5634DF524");
    Log.d(TAG, "Starting to scan for beacons"); 

    // 构建iBeacon制造商数据前缀:0x0215 + UUID字节
    ByteBuffer manufacturerDataBuffer = ByteBuffer.allocate(18);
    manufacturerDataBuffer.put((byte) 0x02); // iBeacon类型长度
    manufacturerDataBuffer.put((byte) 0x15); // iBeacon类型
    manufacturerDataBuffer.putLong(targetUuid.getMostSignificantBits());
    manufacturerDataBuffer.putLong(targetUuid.getLeastSignificantBits());
    byte[] manufacturerDataPrefix = manufacturerDataBuffer.array();

    ScanFilter scanFilter = new ScanFilter.Builder()
        .setManufacturerData(0x004C, manufacturerDataPrefix, null) // 匹配前缀,后缀不限制
        .build();

    ScanSettings scanSettings = new ScanSettings.Builder() 
        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 
        .build(); 

    instance.scanningSubscription = instance.rxBleClient.scanBleDevices(scanSettings, scanFilter) 
        .subscribe(new Observer<ScanResult>() { 
            @Override 
            public void onCompleted() { } 
            @Override 
            public void onError(Throwable e) { 
                Log.e(TAG, "Bluetooth scanning error", e); 
            } 
            @Override 
            public void onNext(ScanResult scanResult) { 
                instance.processScanResult(scanResult); 
            } 
        }); 
}

补充说明

  • RxAndroidBle本身并没有专门封装iBeacon的解析逻辑,所以需要你自己处理广播数据的解析,或者可以引入专门的iBeacon解析库来简化操作,但如果只需要基础的UUID匹配,上面的工具方法足够。
  • 注意权限:确保你的应用已经申请了BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE、BLUETOOTH_CONNECT权限(Android 12+),或者旧版本的ACCESS_FINE_LOCATION权限,并且定位服务已经开启。

内容的提问来源于stack exchange,提问作者LucasHood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 08:12:46