繁体   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