【问题标题】:Broadcast not triggered when using bluetoothLEScanner().startScan使用 bluetoothLEScanner().startScan 时未触发广播
【发布时间】:2020-03-08 18:13:16
【问题描述】:

当设备进入具有特定 UUID 的信标区域时,我试图唤醒我的应用程序。

到目前为止,我尝试使用本机 BluetoothAdapter.getBluetoothLeScanner,提供 PendingIntent 来启动广播接收器。

我还尝试了RxBleClient,这是一个很棒的库,在进行常规发现时确实有效。

我尝试了AltBeacon lib,这也是一个非常彻底和出色的 lib。

我也试过玩服务 Nearby Apis。

但一切都失败了。他们都可以定期扫描信标,但在尝试基本时,注册并让设备在 bg 中进行扫描。广播永远不会被触发。

我在使用前台服务时也尝试了所有 4 个。那也没有帮助。 我还要提到这一切都是在 Android 8 上完成的。 我查看了两个库中的代码,它们最终都使用了来自本地蓝牙适配器的相同函数调用。所以我假设如果失败,其他一切也会失败。 我还会提到,当为 startScan 函数提供 CallBack 而不是 PendingIntent 时,所有扫描的 BT 设备都会不断触发回调。如果我添加一个 ScanFilter 来过滤我的 UUID,它会失败。 我错过了什么?

顺便说一句,当我在 Ios 中实现它时,它完美无缺。应用程序被唤醒,就好像我使用了地理围栏进入/退出触发器一样。

为什么这在 Android 中不起作用? 有什么想法吗?

编辑: 这就是我使用 AltBeacon 库中的代码的方式。它基本上是 DOCS 教程的复制粘贴。唯一的区别是我将它封装在一个单独的类中:

public void init(AppCompatActivity context) {
    if (isRegistered) {
        return;
    }

    BluetoothManager bluetoothManager = (BluetoothManager) context.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
    if (bluetoothManager != null) {
        bluetoothAdapter = bluetoothManager.getAdapter();
        if (!bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            context.startActivityForResult(enableBtIntent, 1002);
        } else {
            register(context);
        }
    }
}

public void register(AppCompatActivity context) {

    if (isRegistered) {
        return;
    }

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            Region region = new Region("com.sample.WakeOnDiscovery", Identifier.parse("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"), Identifier.fromInt(11180), null);
            bootstrapRegion = new RegionBootstrap(new BootstrapNotifier() {
                @Override
                public Context getApplicationContext() {
                    return Application.getContextFromApplicationClass();
                }

                @Override
                public void didEnterRegion(Region region) {
                    Logger.log(TAG, "didEnterRegion: " + region.toString());
                }

                @Override
                public void didExitRegion(Region region) {
                    Logger.log(TAG, "didExitRegion: " + region.toString());
                }

                @Override
                public void didDetermineStateForRegion(int i, Region region) {
                    Logger.log(TAG, "didDetermineStateForRegion: " + region.toString() + "|" + i);
                }
            }, region);
        }
    });

    isRegistered = true;
}

这是我尝试扫描此特定 UUID 和主要 int(并且没有主要 int)的时候。一旦我想,只有 didDetermineStateForRegion 被触发。 int i = 0 或 1。

关于 UUID,我尝试了 2 个不同的 UUID。第一个是我在 IOS 中编写的示例应用程序中生成的。 ios 应用程序将自己宣传为信标。我可以在使用常规发现功能的不同应用程序中看到它。 但是 onEnterRegion 没有触发。

我还尝试了多年以来经常使用的 iBeacon 设备的 UUID。 还是没有骰子。

当我尝试使用本机 android ble 扫描仪时,我使用这个:

ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();
    List<ScanFilter> filters = new ArrayList<>(); // Make a scan filter matching the beacons I care about
    filters.add(new ScanFilter.Builder()/*.setServiceUuid(ParcelUuid.fromString("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"))*/.build());
    bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, getPendingIntent(context));

和:

private PendingIntent getPendingIntent(Context context) {
    return PendingIntent.getBroadcast(context, 0, new Intent(context, BTDiscoveryBroadcast.class), PendingIntent.FLAG_UPDATE_CURRENT);
}

我尝试将 null 作为过滤器传递,我尝试了一个空数组列表,我尝试了一个具有相同 UUID 的实际过滤器。

仍然没有任何效果。

我在 logcat 中偶然看到的是这个错误消息:

E/NearbyDirect: Could not start scan. [CONTEXT service_id=49 ]
java.lang.IllegalStateException: Receiver com.google.location.nearby.direct.bluetooth.state.FastPairScanner$4@535d6ea registered with differing handler (was Handler (adxv) {8fab16a} now Handler (android.app.ActivityThread$H) {e4e0078})

我认为在使用 AltBeacon 库时也会发生这种情况。我只能假设这与我的问题有关。

编辑 2: 我试过这个:

ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();
            List<ScanFilter> filters = new ArrayList<>(); // Make a scan filter matching the beacons I care about
            byte[] manufacturerData = new byte[] {
                    // iBeacon identifier prefix
                    0x02, 0x15,
                    // Your Proximity UUID
                    (byte) 0xE2, (byte) 0xC5, 0x6D, (byte) 0xB5, (byte) 0xDF, (byte) 0xFB, 0x48, (byte) 0xD2, (byte) 0xB0, 0x60, (byte) 0xD0, (byte) 0xF5, (byte) 0xA7, 0x10, (byte) 0x96, (byte) 0xE0,
                        0x3, 0x20, 0x3, 0x20, (byte) 0xC5
            };
            int manufacturerId = 0x004c; // Apple
            filters.add(new ScanFilter.Builder().setManufacturerData(manufacturerId, manufacturerData).build());
            bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, getPendingIntent(context));

我在进行常规 .startDiscovery 扫描、定位我的 bt 设备并从 ScanResult 中提取数据后检索到的字节数据。只是为了确保它完全相同。

仍然没有触发广播:(

【问题讨论】:

  • 问题可能出在您的 ScanFilter 上。请显示您的代码我在 Android 信标库中编写了实现,该库始终使用带有此意图支持扫描的扫描过滤器。如果您正确设置扫描过滤器,我可以确认它确实有效并且对 iOS 同样可靠。
  • @davidgyoung 嗨,David,首先请允许我感谢您提供了令人惊叹的 AltBeacon 库。我们已经使用它多年了,它太棒了!做这项工作并且做得很好。我用代码编辑了我的 OP。感谢您的帮助。
  • 我认为你需要退后一步才能解决这个问题。什么有效?你能在任何情况下用你的代码检测到你的信标吗?你确定你知道你的信标标识符吗?是否还有其他根本性问题,例如缺少蓝牙或位置权限?
  • 已授予权限。蓝牙已启用。有两种方法有效。首先,当我简单地调用 bluetoothAdapter.startDiscovery() 时。随着广播接收器被触发,我看到了所有被扫描的设备。但这不是背景扫描。我可以简单地用间隔调用它并不时扫描。这不是我要找的。第二种可行的方法是为 getBluetoothLeScanner().startScan 调用提供回调而不是挂起的意图。这里的问题是添加过滤器时。回调停止。虽然标识符是正确的。
  • 这里有根本性的错误。 startDiscovery 调用是蓝牙经典操作。它不应直接影响 BLE 扫描。它突然导致您获得 BLE 扫描结果的事实表明它正在解除阻塞作为副作用。也许您的代码以某种方式阻止了 Android 用于发送 BLE 意图回调的线程,并且执行 startDiscovery 以某种方式重置蓝牙以解除阻止这些线程。

标签: android beacon altbeacon google-beacon-platform


【解决方案1】:

如果您想设置扫描过滤器来查找信标 UUID,这样的代码将不起作用:

filters.add(new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0")).build());

上面的代码将设置一个过滤器来寻找一个 BLE 设备,该设备发布一个 GATT 服务 UUID 匹配 E2C56DB5-DFFB-48D2-B060-D0F5A71096E0。 GATT Service UUID 与 Bluetooth Beacon Proximity UUID 完全无关,即使两个 UUID 表面上看起来相同。换句话说,您是在告诉过滤器寻找可连接的蓝牙设备,该设备会宣传恰好与您的信标标识符相同的自定义服务。这将永远找不到任何东西,因为这样的设备几乎可以保证不存在。

您想要做的事情反而更复杂 - 您想要设置一个扫描过滤器来查找蓝牙 LE 制造商广告(即 iBeacon 和 AltBeacon 广告),该广告具有特定的制造商代码并以某个特定的开头字节序列。

获取过滤器的确切字节序列很棘手,因为它取决于制造商 ID 和信标布局(iBeacon 或 AltBeacon)。这是 Android 信标库为您处理的众多复杂问题之一。

如果你真的需要自己做,你会为 iBeacon 做这样的事情(警告:未经测试的代码):

byte[] manufacturerData = new byte[] {
            // iBeacon identifier prefix
            0x02, 0x15, 
            // Your Proximity UUID
            0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2, 0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0
            };
int manufacturerId = 0x004c; // Apple
ScanFilter filter =
filters.add(new ScanFilter.Buider().setManufacturerData(manufacturerId, manufacturerData).build());

【讨论】:

  • 我现在就试试这个。但它仍然没有回答为什么在不提供任何过滤器时,广播不会在任何类型的 bt 发现上被触发。正如我所提到的,我尝试在不提供任何过滤器的情况下进行扫描。仅扫描设置未决意图,仅此而已。我附近有很多信标和 bt 设备。仍然没有触发广播......我希望当不提供过滤器时,任何bt广告都会触发广播。不会吗?
  • intent-backed API 旨在与过滤器一起使用,否则通过 Intent 发送每一个蓝牙数据包检测对操作系统来说过于繁重。我怀疑如果您不提供过滤器,它甚至不起作用,尽管您必须检查文档或 Android 源来确认。
  • 我尝试了 .startDiscovery 扫描。找到我正在寻找的 bt 设备,提取其制造商数据(字节)并将其用作过滤器。 (在最后一次编辑中显示)......它仍然没有工作。我也觉得我错过了一些东西。但是实在看不出来是什么。代码真的很简单。它应该工作!大声笑:)
  • 最后,我们决定使用 RxBleClient 自己启动扫描,然后使用 BeaconParser(来自 AltBeacon)解析设备字节数据并检查其 UUID。扫描正在间隔执行(远程参数)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多