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

已配置蓝牙权限仍遭Android Studio权限检查提示的求助

解决Android蓝牙Socket连接的权限警告问题

我用HC-05模块实现Arduino向Android传输串口数据,已经在AndroidManifest.xml配置了蓝牙权限,也在MainActivity里加了权限申请和onRequestPermissionsResult处理逻辑,但调用bluetoothSocket.createRfcommSocketToServiceRecord(MY_UUID)和bluetoothSocket.connect()时,Android Studio仍提示:

Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException

尝试添加权限申请结果处理和前置判断后错误依然存在,以下是具体解决步骤:


问题根源

代码仅适配了Android 11及以下的旧版蓝牙权限(BLUETOOTH、BLUETOOTH_ADMIN),但Android 12(API 31)及以上引入了细分权限BLUETOOTH_CONNECT和BLUETOOTH_SCAN;同时initBluetooth方法内未再次确认权限状态(用户可能在运行时撤销权限),导致IDE检测到权限风险。


具体修复步骤

1. 动态适配不同版本的权限数组

根据系统版本返回对应权限,替代原固定数组:

private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1;

// 动态获取对应版本的蓝牙权限
private String[] getBluetoothPermissions() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        return new String[]{
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_SCAN
        };
    } else {
        return new String[]{
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN,
                Manifest.permission.ACCESS_FINE_LOCATION
        };
    }
}

需导入android.os.Build包

2. 更新权限检查与申请逻辑

修改onCreate中的权限判断,覆盖所有需要的权限:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    fastestTextView = findViewById(R.id.fastest_text_view);
    slowestTextView = findViewById(R.id.slowest_text_view);
    averageTextView = findViewById(R.id.average_text_view);

    // 检查所有必要权限是否已授予
    boolean hasAllPermissions = true;
    for (String permission : getBluetoothPermissions()) {
        if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            hasAllPermissions = false;
            break;
        }
    }

    if (!hasAllPermissions) {
        ActivityCompat.requestPermissions(this, getBluetoothPermissions(), REQUEST_BLUETOOTH_PERMISSIONS);
    } else {
        initBluetooth();
    }
}

3. 在initBluetooth开头添加二次权限检查

即使权限已申请通过,也要在调用蓝牙API前再次确认(防止用户中途撤销):

private void initBluetooth() {
    // 二次检查权限,避免运行时权限被撤销
    boolean hasAllPermissions = true;
    for (String permission : getBluetoothPermissions()) {
        if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            hasAllPermissions = false;
            break;
        }
    }
    if (!hasAllPermissions) {
        ActivityCompat.requestPermissions(this, getBluetoothPermissions(), REQUEST_BLUETOOTH_PERMISSIONS);
        return;
    }

    // 原有蓝牙初始化逻辑
    bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        Toast.makeText(this, "蓝牙不被设备支持", Toast.LENGTH_SHORT).show();
        finish();
        return;
    }

    if (!bluetoothAdapter.isEnabled()) {
        Toast.makeText(this, "请开启蓝牙", Toast.LENGTH_SHORT).show();
        finish();
        return;
    }

    bluetoothDevice = bluetoothAdapter.getRemoteDevice(MAC_ADDRESS);
    try {
        bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
        bluetoothSocket.connect();
        inputStream = bluetoothSocket.getInputStream();
        reader = new BufferedReader(new InputStreamReader(inputStream));
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        final String data = reader.readLine();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                fastestTextView.setText(data);
                                slowestTextView.setText(data);
                                averageTextView.setText(data);
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        // 显式捕获权限不足异常,避免崩溃
        Toast.makeText(this, "蓝牙权限不足,无法连接", Toast.LENGTH_SHORT).show();
        e.printStackTrace();
    }
}

4. 更新权限申请结果处理逻辑

确保所有权限都被授予才继续执行:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (allGranted) {
            initBluetooth();
        } else {
            Toast.makeText(this, "需要蓝牙权限才能继续", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
}

额外说明

  • Android 12+的BLUETOOTH_CONNECT是连接已配对设备的核心权限,BLUETOOTH_SCAN用于设备扫描(若你的流程不需要扫描可移除)
  • 显式捕获SecurityException可避免程序崩溃,同时给用户明确提示
  • 权限检查需覆盖所有调用蓝牙API的入口,防止权限状态变化引发异常

内容的提问来源于stack exchange,提问作者developpy97

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:20:22