You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:47:03