簡體   English   中英

無法掃描或發現 android 中的 BT 和 BLE 設備

[英]Unable to scan or discover BT and BLE devices in android

我是 Java 和 Android 的完全新手。我正在嘗試創建一個測試應用程序來監聽附近的 BLE 和 BT 設備。 我有另一個設備,我在其中編寫了一些邏輯來廣播其 BLE 信標。 我使用 Playstore 應用驗證了它。 現在我正在嘗試在 Android 上編寫自己的應用程序。我一直在閱讀 Android 開發人員頁面以獲取指導。 我確實遵循了以下頁面的每一步

https://developer.android.com/guide/topics/connectivity/bluetooth/setup

https://developer.android.com/guide/topics/connectivity/bluetooth/permissions

https://developer.android.com/guide/topics/connectivity/bluetooth/find-bluetooth-devices

https://developer.android.com/guide/topics/connectivity/bluetooth/find-ble-devices

另外,請注意,我使用了 Android 開發者頁面中的 BARE MINIMUM CODE所以這就是我所做的。

1. 首先我在 AndroidManifest 下添加了我的權限

注意 1:我正在將此應用程序部署到運行 Android 11 的手機

注 2:所有這些代碼都寫在 MainActivity 中。 我還沒有創建任何其他活動 class

<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

2. 接下來我檢查我的 BT 是否啟用。

        if (bluetoothAdapter == null) {
            blefinder.append("\nDEVICE DOES NOT SUPPORT BLUETOOTH");
        }
        else {
            blefinder.append("\nDEVICE SUPPORTS BLUETOOTH");
        }

我收到了 BT 當然已啟用的成功消息

3.接下來我檢查我的設備是否支持BLE

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            blefinder.append("\nBLE NOT SUPPORTED ON THIS DEVICE : ");
            finish();
        }
        else{
            blefinder.append("\nBLE IS SUPPORTED ON THIS DEVICE : ");
        }

我收到支持 BLE 的消息

4.接下來我列出我已經配對/綁定的設備

為此,我調用ListPairedAndBondedDevices(); 在上述步驟之后的 onCreate() 本身。 Function 定義如下。

private void ListPairedAndBondedDevices(){
        @SuppressLint("MissingPermission") Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

        if (pairedDevices.size() > 0) {
            // There are paired devices. Get the name and address of each paired device.
            blefinder.append("\nPAIRED/BONDED DEVICES");
            for (BluetoothDevice device : pairedDevices) {
                blefinder.append("\n" + device.getName() + " | " + device.getAddress());
            }
        }
    }

這也很有效,可以打印出我配對的設備。 接下來的兩部分是我面臨的問題。

5. 問題步驟 | 第1部分:

在這里,我注冊了一個廣播接收器來發現附近的所有 BT 設備。 我已經取消綁定我的 BT 耳機並將其保持在配對模式以驗證這一點。

ListPairedAndBondedDevices(); // From previous code snippet
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); // New code statement 
registerReceiver(BTReceiver, filter);// New code statement 

廣播接收器實現

    private final BroadcastReceiver BTReceiver = new BroadcastReceiver() {
        @SuppressLint("MissingPermission")
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Discovery has found a device. Get the BluetoothDevice
                // object and its info from the Intent.
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                blefinder.append("\n" + device.getName() + " | " + device.getAddress());

            }
        }
    };

所以這部分沒有工作:(

如果您在上面看到,我在列出已經配對的設備(通過調用ListPairedAndBondedDevices() )后立即在onCreate中注冊BTReceiver

當我運行調試器時,這個廣播接收器永遠不會被調用。

6.問題步驟| 第2部分:

在此之后,我也嘗試通過scanLeDevice()來掃描 BLE 設備

ListPairedAndBondedDevices(); // From previous snippet
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); // From previous snippet
registerReceiver(BTReceiver, filter);// From previous snippet
scanLeDevice(); // ---------------->>> CALLING THIS FUNCTION TO SCAN FOR BLE DEVICES

scanLeDevice() 的實現

    private void scanLeDevice() {
        if (!scanning) {
            // Stops scanning after a predefined scan period.
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scanning = false;
                    bluetoothLeScanner.stopScan(leScanCallback);
                    blefinder.append("\nSTOPPING BLE SCAN... TIMEOUT REACHED");
                }
            }, SCAN_PERIOD);

            scanning = true;
            bluetoothLeScanner.startScan(leScanCallback);
        } else {
            scanning = false;
            bluetoothLeScanner.stopScan(leScanCallback);
            blefinder.append("\nSTOPPING BLE SCAN");
        }
    }

不幸的是,這也失敗了。 調試器告訴我這部分代碼正在被調用。 SCAN_PERIOD (我設置的超時)30 秒后,我收到掃描已停止的消息( STOPPING BLE SCAN

現在我也實現了leScanCallback (即設備掃描回調)

    private ScanCallback leScanCallback =
            new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    super.onScanResult(callbackType, result);
                    blefinder.append("SOMETHING GOT SCANNED?");
                    blefinder.append("\n"+result.getDevice().toString());
                //  leDeviceListAdapter.addDevice(result.getDevice());
                //  leDeviceListAdapter.notifyDataSetChanged();
                }
            };

請注意,我沒有使用ListAdapter ,因為我不知道這個概念。 因此,對於初學者來說,我只是想將結果轉儲到由 blefinder 表示的blefinder中。 這個blefinder打印了所有其他文本,因此 TextView 變量沒有任何問題。 當我使用調試器運行時,它根本沒有進入leScanCallback代碼定義,即使在 30 秒后,在執行scanLeDevice() function 之后也是如此。

我在這里有點迷路了。 有什么我可能遺漏或做錯的事情嗎? 它應該很簡單,列出我附近的 ble/bt 設備。

如果我錯過了,我很樂意分享任何進一步的信息。 請在評論中告訴我。

首先,您應該檢查您的應用程序是否在設置應用程序 > 應用程序 <your_app> > 權限中獲得了位置權限。 一些權限(如 ACCESS_*_LOCATION 和 BLUETOOTH_ADMIN)需要在運行時請求並由用戶通過彈出窗口授予。 通常,在嘗試執行需要您的應用程序沒有的權限的代碼時,您應該會收到 SecurityException 或 logcat 警告,但 android 跳過錯誤處理的情況並不少見。

考慮使用此方法開始掃描,以便檢查其結果代碼以獲取有關正在(未)發生的事情的潛在附加信息。

您還可以通過記錄 BTReceiver.onReceive() 中收到的所有操作來獲得一些線索,而不僅僅是找到的操作。

最后檢查您設備上的位置設置是否已打開藍牙掃描(設置應用>位置> wifi和藍牙掃描)

假設您已完成我在評論中提到的權限,我們可以實現一個干凈的藍牙 LE 掃描器 object,然后在 UI 中使用它。

首先我們實現一個結果消費者接口,以便將結果傳遞給調用BleScanner.scan()方法的消費者。

public interface ScanResultConsumer {

    public void onDeviceFound(BluetoothDevice device, byte[] scanRecord, int rssi);
    public void onScanningStarted();
    public void onScanningStopped();
}

現在我們需要實現管理掃描事件的掃描儀 object:

public class BleScanner {
    private static final String TAG = BleScanner.class.getSimpleName();

    private BluetoothLeScanner leScanner = null;
    private BluetoothAdapter bleAdapter = null;
    private Handler uiHandler = new Handler(Looper.getMainLooper);
    private ScanResultConsumer scanResultConsumer;
    private boolean scanning = false;
    private final ArrayList<BluetoothDevice> foundDeviceList = new ArrayList<>();

    public BleScanner(Context context) {
        final BluetoothManager bluetoothManager = (BluetoothManager)
                context.getSystemService(Context.BLUETOOTH_SERVICE);

        bleAdapter = bluetoothManager.getAdapter();
        if(bleAdapter == null) { 
            Log.d(TAG, "No bluetooth hardware.");
        }
        else if(!bleAdapter.isEnabled()){
            Log.d(TAG, "Blutooth is off.");
        }
    }

    public void scan(ScanResultConsumer scanResultConsumer, long scanTime){
        foundDeviceList.clear();
        if (scanning){
            Log.d(TAG, "Already scanning.");
            return;
        }
        Log.d(TAG, "Scanning...");
        if(leScanner == null){
            leScanner = bleAdapter.getBluetoothLeScanner();
        }

        if(scanTimeMs > 0) {
            uiHandler.postDelayed(()-> {
                if (scanning) {
                    Log.d(TAG, "Scanning is stopping.");
                    if(leScanner != null)
                        leScanner.stopScan(scanCallBack);
                    else
                        Log.d(TAG,"Scanner null");
                    setScanning(false);
                }
            }, scanTimeMs);
        }

        this.scanResultConsumer = scanResultConsumer;
        leScanner.startScan(scanCallBack);
        setScanning(true);
    }


    private final ScanCallback scanCallBack = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            if (!scanning){
                return;
            }

            if(foundDeviceList.contains(result.getDevice())) {
                // This device has already been found
                return;
            }

            // New device found, add it to the list in order to prevent duplications
            foundDeviceList.add(result.getDevice());

            if(scanResultConsumer != null) {
                uiHandler.post(() -> {
                    scanResultConsumer.onDeviceFound(result.getDevice(),
                            result.getScanRecord().getBytes(), result.getRssi());
                });
            }
        }
    };

    public boolean isScanning(){
        return scanning;
    }

    void setScanning(boolean scanning){
        this.scanning = scanning;
        uiHandler.post(() -> {
            if(scanResultConsumer == null) return;
            if(!scanning){
                scanResultConsumer.onScanningStopped();
                // Nullify the consumer in order to prevent UI crashes
                scanResultConsumer = null;
            } else{
                scanResultConsumer.onScanningStarted();
            }
        });
    }
}

最后,我們可以在任何需要的地方使用這個干凈的實現。 但請注意,必須提供上下文才能創建BleScanner object。

public class MainActivity extends AppCompatActivity {

    private BleScanner bleScanner;
    private Button buttonScan
    // Other codes...


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Other codes...
        bleScanner = new BleScanner(getApplicationContext());
        // Other codes...

        // For example if you want to start scanning on a button press
        // Let's say you have a button called buttonScan and initiated it
        buttonScan = findViewById(R.id.scan_button);

        buttonScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bleScanner.scan(new ScanResultConsumer {

                    @Override
                    public void onDeviceFound(BluetoothDevice device, byte[] scanRecord, int rssi) {
                        // TODO Here you have a newly found device, do something.
                    }

                    @Override
        q           public void onScanningStarted() {
                        // TODO Scanning has just started, you may want to make some UI changes.
                    }

                    @Override
                    public void onScanningStopped() {
                        // TODO Scanning has just stopped, you may want to make some UI changes.
                    }
                });
            }
        });
    }

}

注意:我在普通編輯器中編寫了這段代碼,而不是在 Android Studio 中。 所以可能會有一些錯誤,如果有的話請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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