[英]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.