簡體   English   中英

檢測 Android 中的 BLE 設備名稱更改

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM