Android开发已配置蓝牙权限仍报BLUETOOTH_CONNECT错误崩溃
Android 蓝牙开启报BLUETOOTH_CONNECT权限缺失崩溃修复方案
核心崩溃原因
- 最直接触发点:权限校验位置错误。Android 12(API 31)及以上版本中,哪怕只是调用
BluetoothAdapter.isEnabled()查询蓝牙状态,也要求持有BLUETOOTH_CONNECT权限。你的代码把权限检查写在了if (!adapter.isEnabled())的代码块内部,等于执行isEnabled()时还没做权限校验,直接触发权限拦截崩溃。 - 未实现运行时权限申请逻辑。
BLUETOOTH_CONNECT属于危险运行时权限,仅在AndroidManifest.xml中声明、仅调用checkSelfPermission判断权限状态是不够的,检测到无权限时必须主动调用系统API弹出授权窗口,让用户手动同意。 - 空指针逻辑漏洞。判断
adapter == null时仅弹出了无蓝牙设备的提示,没有加return终止方法执行,在无蓝牙模块的设备上,后续代码调用adapter相关方法会直接触发空指针崩溃。 - 逻辑笔误。
else分支对应蓝牙已经处于开启状态的场景,你打印的日志是"Not enabled",和实际逻辑相反。
分步修复方案
1. 补全运行时权限申请逻辑
首先在代码中添加权限检查、申请的通用逻辑,注意区分系统版本:
// 蓝牙权限请求码 private static final int REQUEST_BT_PERMISSIONS = 1001; // 蓝牙开启请求码 private static final int REQUEST_ENABLE_BT = 1002; // 需要申请的蓝牙权限列表,按系统版本适配 private static final String[] BT_PERMISSIONS; static { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { BT_PERMISSIONS = new String[]{ Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN }; } else { // Android11及以下不需要新蓝牙权限 BT_PERMISSIONS = new String[]{}; } } // 检查是否已持有蓝牙权限 private boolean hasBTPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { for (String permission : BT_PERMISSIONS) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; } // 发起蓝牙权限申请 private void requestBTPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ActivityCompat.requestPermissions(this, BT_PERMISSIONS, REQUEST_BT_PERMISSIONS); } } // 处理权限申请回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_BT_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { // 权限全部通过,再执行蓝牙开启逻辑 enableBLT(); } else { // 权限被拒绝,可以在这里弹框提示用户需要权限才能使用蓝牙功能 Log.d("blt-", "蓝牙权限被用户拒绝"); } } }
2. 修正enableBLT方法的执行顺序
把权限检查、空指针判断移到方法最前面,修正后代码如下:
private void enableBLT(){ // 先检查权限,无权限直接发起申请,终止后续执行 if (!hasBTPermissions()) { requestBTPermissions(); return; } BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); // 无蓝牙模块时弹提示后直接return,避免空指针 if (adapter == null) { dialogNoBlt(); return; } // 此时已持有权限,调用isEnabled不会触发崩溃 if (!adapter.isEnabled()) { Intent enableBltIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBltIntent, REQUEST_ENABLE_BT); } else { // 修正原来写反的日志 Log.d("blt-", "蓝牙已处于开启状态"); } }
3. 优化Manifest权限配置,做版本兼容
给旧版蓝牙权限加上版本上限,避免高版本系统出现冗余权限提示,扫描不需要位置时加标记减少权限申请成本:
<!-- Android11及以下版本需要的旧版蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android12及以上版本需要的新版蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 如果蓝牙扫描不需要获取位置结果,加neverForLocation标记,不需要额外申请位置权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
额外注意事项
- 所有蓝牙相关API调用(包括查询状态、开启/关闭、扫描、配对、连接),在Android12+上都要先确认持有
BLUETOOTH_CONNECT权限,不要抱有“只是查个状态不需要权限”的侥幸。 - 如果用户拒绝权限并勾选了“不再询问”,需要弹框引导用户跳转到应用设置页手动开启权限,否则功能始终无法使用。
- 如果你使用的是较新版本的AndroidX,建议废弃
startActivityForResult和onRequestPermissionsResult,改用ActivityResultContracts处理权限申请、蓝牙开启的回调,代码更简洁也更符合官方开发规范。
内容的提问来源于stack exchange,提问作者Yoyot L
相关产品推荐
相关产品推荐

