Android中BluetoothLEScanner未调用ScanCallback的问题求助
我之前在做Android BLE扫描功能时也踩过一模一样的坑,结合你描述的情况——程序能走到bluetoothLeScanner.stopScan(scanCallback)但自定义BLEScanCallback的回调完全没触发,给你列几个最值得优先排查的方向:
权限是否完全到位
Android不同版本对BLE扫描的权限要求不一样:- Android 11及以下:需要动态申请
ACCESS_FINE_LOCATION(注意是FINE不是COARSE,部分设备COARSE权限无法触发BLE扫描),同时要在Manifest里声明BLUETOOTH、BLUETOOTH_ADMIN权限。 - Android 12+:新增了
BLUETOOTH_SCAN权限,必须动态申请,而且如果是后台扫描还需要额外的ACCESS_BACKGROUND_LOCATION权限。
一定要确认权限申请成功了,比如在onRequestPermissionsResult里打印授权状态,没授权的话扫描会静默失败,不会有任何回调。
- Android 11及以下:需要动态申请
蓝牙状态与设备兼容性
先确认设备本身支持BLE,并且蓝牙处于开启状态:- 用
BluetoothAdapter.isEnabled()判断蓝牙是否开启,没开的话要通过ACTION_REQUEST_ENABLE请求用户打开蓝牙。 - 部分老旧设备可能不支持BLE,可以用
bluetoothAdapter.isMultipleAdvertisementSupported()辅助判断。
- 用
ScanCallback实例是否一致
如果你在调用startScan时new了一个新的ScanCallback,但stopScan用的是另一个实例,那之前的扫描任务不会被正确终止,同时回调也永远不会触发。一定要把ScanCallback作为类的成员变量初始化一次,确保startScan和stopScan用的是同一个对象。扫描过滤条件是否过于严格
如果你设置了ScanFilter(比如指定了特定UUID、设备名),而周围没有符合条件的BLE设备,回调自然不会触发。建议先去掉所有过滤条件,用空的ScanFilter列表启动扫描,测试是否能收到回调。扫描时长是否过短
你提到程序走到了stopScan,会不会是startScan后立刻调用了stopScan?BLE扫描需要一点时间发现设备,尤其是低功耗模式下。可以先注释掉stopScan的逻辑,让扫描持续一段时间,看是否能触发回调。系统限制与电池优化
部分设备的省电模式、后台限制会阻止BLE扫描正常工作。可以先把应用设置为“不优化电池使用”,并在前台状态下测试扫描,排除系统层面的限制。
这里给你一个基础的正确实现示例,你可以对比排查:
// 类成员变量 private BluetoothLeScanner bleScanner; private ScanCallback scanCallback; private static final int REQ_ENABLE_BT = 101; private static final int REQ_BLE_PERMISSIONS = 102; // 初始化BLE相关组件 private void initBLEComponents() { BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); // 检查设备是否支持BLE if (bluetoothAdapter == null || !getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "设备不支持BLE", Toast.LENGTH_SHORT).show(); return; } // 检查蓝牙是否开启 if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQ_ENABLE_BT); return; } // 初始化扫描器和回调(确保是同一个实例) bleScanner = bluetoothAdapter.getBluetoothLeScanner(); scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); Log.d("BLE_SCAN", "发现设备: " + result.getDevice().getName() + " | " + result.getDevice().getAddress()); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); Log.e("BLE_SCAN", "扫描失败,错误码: " + errorCode); } }; } // 启动扫描 private void startBLEScan() { if (bleScanner == null || scanCallback == null) { Toast.makeText(this, "BLE组件未初始化", Toast.LENGTH_SHORT).show(); return; } // 检查权限(适配Android 12+) List<String> requiredPermissions = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.BLUETOOTH_SCAN); } } else { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION); } } if (!requiredPermissions.isEmpty()) { ActivityCompat.requestPermissions(this, requiredPermissions.toArray(new String[0]), REQ_BLE_PERMISSIONS); return; } // 无过滤条件,高优先级扫描 ScanSettings scanSettings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); bleScanner.startScan(null, scanSettings, scanCallback); Toast.makeText(this, "开始BLE扫描", Toast.LENGTH_SHORT).show(); } // 停止扫描 private void stopBLEScan() { if (bleScanner != null && scanCallback != null) { bleScanner.stopScan(scanCallback); Toast.makeText(this, "停止BLE扫描", Toast.LENGTH_SHORT).show(); } } // 权限申请结果回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQ_BLE_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { startBLEScan(); } else { Toast.makeText(this, "缺少必要权限,无法扫描BLE设备", Toast.LENGTH_SHORT).show(); } } }
内容的提问来源于stack exchange,提问作者Josh P.

