[英]Detecting BLE Device name change in Android
我们有一个正在开发的 BLE 设备,它通过设备名称输出数据。 该设备运行正常,可以看到使用 nRF Connect 等应用程序正确更改名称。 但是,在我们自己的 Android 应用程序中,我们很难做到这一点。 我们可以很好地检测到这些设备,但它们几乎永远不会超过最初的名称。
我开始使用的代码有一个在 onResume() 中启动的循环,该循环使用 BluetoothLeScanner 和 startScan() function 进行扫描。
public void BLEScan(final boolean enable){
final int SCAN_PERIOD = 12000;
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
if (enable) {
Log.d(TAG, "Starting Scan");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(false);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
bluetoothLeScanner.flushPendingScanResults(mLeScanCallback);
bluetoothLeScanner.startScan(mLeScanCallback);
} else {
Log.d(TAG, "Stopping Scan");
bluetoothLeScanner.flushPendingScanResults(mLeScanCallback);
bluetoothLeScanner.stopScan(mLeScanCallback);
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(true);
}
}, SCAN_PERIOD);
}
}
并且在基于设备过滤的 mLeScanCallback 中检测到。 基本上,如果它以前没有见过设备,它会将其添加到信标列表中。 但是,如果它以前见过它,它会使用 Beacon 的 seen() function 更新值,并使用 Beacon 的名称作为信息的来源。 在这两种情况下,它都会更新其适配器以填充新信息。
private ScanCallback mLeScanCallback =
new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
final ScanResult res2 = result;
runOnUiThread(new Runnable() {
@Override
public void run() {
BluetoothDevice device = res2.getDevice();
String address = device.getAddress();
if (device.getName() != null){
if (device.getName().contains("ABT:")){
if (!mLeBeacons.containsKey(address)){
BleBeacon beacon = new BleBeacon(device.getName(), address);
bleList.add(beacon);
adapter.notifyDataSetChanged();
mLeBeacons.put(device.getAddress(), beacon);
} else {
for (int x = 0; x < bleList.size(); x++){
if (device.getAddress().equals(bleList.get(x).getMAC())){
bleList.get(x).seen(device.getName());
adapter.notifyDataSetChanged();
}
}
}
}
}
}
});
}
};
但是,即使在更新名称之后,mLeScanCallback 也只会返回原始名称。
经过这里的一些搜索后,我一直在寻找的是使用 function fetchUuidsWithSdp() 和 ACTION_FOUND、ACTION_UUID、ACTION_DISCOVERY_FINISHED 和 ACTION_NAME_CHANGED 等意图来正确查看名称更改。 因此,我将 fetchUuidsWithSdp() 添加到 mLeScanCallback。 然而,虽然这会触发 Intent,但名称仍然没有更新。 我尝试在实际意图中调用 fetchUuidsWithSdp() ,但这也无济于事。 奇怪的是,如果我关闭手机屏幕或离 BLE 设备足够远,ACTION_NAME_CHANGED 偶尔会触发。 但是,所有 onPause() 所做的只是调用super.onPause()
和BLEScan(false)
。 而且,由于这些是我在循环中已经在做的事情,所以我不确定如何在它醒着时将它带入我的代码中。
经过更多搜索,我发现,要使用 fetchUuidsWithSdq() function,您需要使用 BluetoothAdapter 的 startDiscovery() function。 所以,我改变了 BLEScan 来使用它,完全去掉了 mLeScanCallback。
public void BLEScan(final boolean enable){
final int SCAN_PERIOD = 12000;
if (enable) {
Log.d(TAG, "Starting Scan");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(false);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
if (mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
} else {
Log.d(TAG, "Stopping Scan");
mBluetoothAdapter.cancelDiscovery();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(true);
}
}, SCAN_PERIOD);
}
}
然而,当 Intent 之前触发时,它们现在没有触发,即使它们在我的意图过滤器中。 在进行了更多搜索之后,我发现有人说 startDiscovery() 不适用于 Le 设备。 所以,我搜索了你应该使用的东西......这让我一直回到使用 BluetoothLeScanner 的 startScan。 那时,我意识到我绕了一个圈子,需要帮助。
我回顾了整个过程,因为在某些地方,我错过了一些东西。 我只是不知道它在哪里。 我应该使用 startScan() 吗? 我没有正确使用 startDiscovery() 吗? 还是我应该完全使用其他东西? ACTION_NAME_CHANGED 偶尔触发的事实让我想 go 回到那个状态,但是当设备处于唤醒状态时如何让它始终工作?
我认为您可能只是在 android 上遇到缓存问题。 在此处查看此答案以获得可能的解决方案: https://stackoverflow.com/a/50745997/7473793
虽然我没有发现我在原始代码中做错了什么(尽管听起来 Android 在这方面可能只是被破坏了),但我确实找到了一种解决方法。 nRF 的 NFC 工具箱有它的源代码可用,并通过添加的过滤器以及它自己的来自北欧图书馆的 Le 扫描仪进行批量扫描。 这是我的扫描 function 现在的样子:
public void BLEScan(final boolean enable){
final BluetoothLeScannerCompat bluetoothLeScanner = BluetoothLeScannerCompat.getScanner();
final ScanSettings settings = new ScanSettings.Builder()
.setLegacy(false)
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
final List<ScanFilter> filters = new ArrayList<>();
ParcelUuid Uuid = new ParcelUuid(UUID.fromString(uuidString));
filters.add(new ScanFilter.Builder().setServiceUuid(Uuid).build());
if (enable) {
Log.d(TAG, "Starting Scan");
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(false);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
bluetoothLeScanner.startScan(filters, settings, mLeScanCallback);
} else {
BLEService.refreshGatt();
Log.d(TAG, "Stopping Scan");
bluetoothLeScanner.stopScan(mLeScanCallback);
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
BLEScan(true);
}
}, SCAN_PERIOD);
}
}
我的回调如下所示:
private no.nordicsemi.android.support.v18.scanner.ScanCallback mLeScanCallback =
new no.nordicsemi.android.support.v18.scanner.ScanCallback() {
@Override
public void onBatchScanResults(@NonNull final List<no.nordicsemi.android.support.v18.scanner.ScanResult> results) {
runOnUiThread(new Runnable() {
@Override
public void run() {
for (final no.nordicsemi.android.support.v18.scanner.ScanResult result : results){
BluetoothDevice device = result.getDevice();
if (device != null){
String address = device.getAddress();
String name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;
if (!mLeBeacons.containsKey(address)) {
BleBeacon beacon = new BleBeacon(device.getName(), address);
bleList.add(beacon);
adapter.notifyDataSetChanged();
mLeBeacons.put(device.getAddress(), beacon);
} else {
for (int x = 0; x < bleList.size(); x++){
if (device.getAddress().equals(bleList.get(x).getMAC())){
bleList.get(x).seen(device.getName());
adapter.notifyDataSetChanged();
}
}
}
}
}
}
});
}
这似乎奏效了。 不过,您需要将以下内容添加到您的依赖项中。
implementation 'no.nordicsemi.android.support.v18:scanner:1.4.2'
之后,我的名字 ACTION_NAME_CHANGE 意图正确触发并且数据正在更新。
我不确定这是从结果中检索名称的不同方式还是批量扫描。 但是,即使 Nordic 也没有使用标准的 Android BLE 库,我猜这是 go 的最佳方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.