Android BLE扫描权限缺失致应用启动崩溃问题排查求助
Android BLE扫描应用启动崩溃排查与修复
问题概述
开发的Android BLE扫描连接应用,启动MainActivity时持续崩溃,已在Manifest中添加BLE相关权限,但仍触发权限异常。
崩溃日志核心原因
从错误栈可明确:
FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start activity ComponentInfo{...}: java.lang.SecurityException: Need android.permission.BLUETOOTH_SCAN permission for AttributionSource {...}: AdapterService isDiscovering
崩溃触发点为调用bluetoothAdapter.isDiscovering()时,缺少BLUETOOTH_SCAN运行时权限,同时代码存在经典蓝牙与BLE API混淆、广播注册错误等问题。
修复步骤
1. 补充BLUETOOTH_SCAN运行时权限
Android 12+要求BLE扫描必须单独申请BLUETOOTH_SCAN权限,需将其加入权限检查和请求列表:
// 权限检查与请求部分 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_SCAN }, REQUEST_FINE_LOCATION); }
2. 替换为BLE专用扫描API
当前使用的startDiscovery()是经典蓝牙扫描API,无法高效适配BLE设备,需改用BluetoothLeScanner:
private BluetoothLeScanner bleScanner; private ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); BluetoothDevice device = result.getDevice(); String deviceName = device.getName() != null ? device.getName() : "Unknown Device"; String deviceAddress = device.getAddress(); String deviceInfo = deviceName + "\n" + deviceAddress; if (!deviceList.contains(deviceInfo)) { deviceList.add(deviceInfo); // 确保UI操作在主线程执行 runOnUiThread(() -> adapter.notifyDataSetChanged()); } } }; private void startBluetoothScan() { if (isScanning) { stopScan(); return; } bleScanner = bluetoothAdapter.getBluetoothLeScanner(); ScanSettings scanSettings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); bleScanner.startScan(null, scanSettings, scanCallback); handler.postDelayed(this::stopScan, SCAN_PERIOD); isScanning = true; scan.setText("Stop Scan"); } public void stopScan() { if (isScanning && bleScanner != null) { bleScanner.stopScan(scanCallback); } scan.setText("Scan Again"); handler.removeCallbacksAndMessages(null); isScanning = false; imageView.setImageResource(R.drawable.bluetoothscanningfail); }
3. 修复广播接收器注册错误
bluetoothStateReceiver监听蓝牙状态变化,但之前用了错误的过滤器注册,同时要避免重复注册/注销引发异常:
@Override protected void onStart() { super.onStart(); // 注册蓝牙状态变化广播,使用正确的IntentFilter registerReceiver(bluetoothStateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); } @Override protected void onStop() { super.onStop(); stopScan(); try { unregisterReceiver(bluetoothStateReceiver); } catch (IllegalArgumentException e) { // 接收器未注册时忽略异常 e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); stopScan(); try { unregisterReceiver(bluetoothStateReceiver); } catch (IllegalArgumentException e) { e.printStackTrace(); } }
4. 移除冗余代码
删除onCreate中权限通过后重复设置的scan按钮点击监听,保留一次即可。
额外注意事项
- Manifest中可给
BLUETOOTH_SCAN添加android:usesPermissionFlags="neverForLocation"(无需通过BLE获取位置时),简化权限申请流程。 - BLE设备连接后,需在
BluetoothGattCallback的onConnectionStateChange中调用discoverServices(),并在使用完BluetoothGatt后调用close()释放资源。 - 确保所有UI更新操作在主线程执行,避免ANR或崩溃。
内容的提问来源于stack exchange,提问作者UncannyHarmony
相关产品推荐
相关产品推荐

