Android蓝牙发现功能异常:扫描无回调问题求助
解决Android蓝牙扫描收不到BroadcastReceiver回调的问题
嘿,我看了你遇到的蓝牙扫描没触发ACTION_FOUND回调的问题,结合你的代码和日志来看,核心问题大概率是权限缺失,还有几个小细节需要调整,我帮你一步步解决:
一、核心问题:权限不足(Android 6.0+必现)
从Android 6.0(API Level 23)开始,蓝牙扫描需要位置权限(ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION),因为系统把蓝牙扫描和位置服务绑定了——如果没有位置权限,系统会直接阻止蓝牙设备发现,自然收不到ACTION_FOUND的广播。
另外如果你的测试设备是Android 12(API Level 31)及以上,还需要新增蓝牙专属权限。
二、具体修复步骤
1. 补充AndroidManifest.xml权限
打开你的AndroidManifest.xml,添加以下权限和功能声明:
<!-- 基础蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 6.0+ 蓝牙扫描需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 12+ 专属蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 声明设备支持蓝牙 --> <uses-feature android:name="android.hardware.bluetooth" android:required="true" />
2. 动态申请位置权限(API 23+)
因为位置权限是危险权限,必须在运行时申请,不能只靠Manifest。修改你的ScanOnClick方法,先检查权限再启动扫描:
private static final int REQUEST_LOCATION_PERMISSION = 2; public void ScanOnClick(View v) { Log.i("NKNKNK","SCAN button clicked"); if (BA == null) { BA = BluetoothAdapter.getDefaultAdapter(); } if (!BA.isEnabled()) { Log.i("NKNKNK", "Bluetooth is not enabled"); return; } // 检查位置权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); return; } // 权限已获取,启动扫描 if (BA.isDiscovering()) { BA.cancelDiscovery(); } Log.i("NKNKNK","Starting discovery logged"); BA.startDiscovery(); }
还要添加权限申请结果的回调:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限通过,重新启动扫描 if (BA != null && BA.isEnabled() && !BA.isDiscovering()) { BA.startDiscovery(); } } else { Log.i("NKNKNK", "Location permission denied, cannot scan Bluetooth devices"); // 可以提示用户需要权限才能扫描 } } }
3. 完善BroadcastReceiver的IntentFilter(可选但推荐)
只监听ACTION_FOUND不够直观,建议添加扫描开始和结束的广播,方便调试:
修改onCreate里的IntentFilter注册:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ... 其他代码 ... IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter); // 初始化BluetoothAdapter BA = BluetoothAdapter.getDefaultAdapter(); }
然后在mReceiver里添加对应处理:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { Log.i("NKNKNK","onReceive method"); String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); Log.i("NKNKNK","Device found: " + device.getName() + "; MAC " + device.getAddress()); } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { Log.i("NKNKNK", "Bluetooth discovery started"); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { Log.i("NKNKNK", "Bluetooth discovery finished"); } } };
4. 优化BluetoothAdapter实例获取
不要在ScanOnClick里重复获取BA,直接在onCreate里初始化一次即可,避免不必要的系统调用。
三、测试验证
- 重新编译安装APP
- 打开蓝牙后,点击扫描按钮,会弹出位置权限申请对话框,允许权限
- 此时查看日志,应该能看到
Bluetooth discovery started,然后陆续收到Device found的日志
内容的提问来源于stack exchange,提问作者Nizarkh




