Android蓝牙权限请求对话框不显示问题及异常排查求助
我已经花了一天时间排查这个问题,还是毫无头绪。查了大量同类问题,试了所有建议,都没用。
我的应用有个设置界面,用户可以在这里开启蓝牙。设置界面会给MainActivity发送Intent,后者会检查安全权限,需要的话就发起权限请求。
我针对SDK 32开发,Manifest配置如下:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
在MainActivity里我会检查权限是否已授予:
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), CustomIntent.CHECK_BLUETOOTH_SECURITY_PERMISSION)) { int check = ContextCompat.checkSelfPermission( thisActivity, Manifest.permission.BLUETOOTH_CONNECT ); if ( check == PackageManager.PERMISSION_DENIED ) getPermission( Manifest.permission.BLUETOOTH_CONNECT, RequestCodes.BT_SECURITY_REQUEST.ordinal() ); } } };
如果权限没授予就发起请求。我试过旧的权限请求方式:
public void getPermission( String permission, int requestCode ) { if ( shouldShowRequestPermissionRationale( permission ) ) { // TODO: display a dialog to explain the reason for needing the permission Toast.makeText( this, "需要说明权限申请的原因", Toast.LENGTH_LONG ).show(); } else { requestPermissions( new String[]{ permission }, requestCode ); } }
我既试过用CompactActivity.requestPermissions,也试过上面直接调用requestPermissions的方式。
同时也试了新的权限请求方式,在onCreate里注册:
activityResultLauncher = registerForActivityResult( new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() { @Override public void onActivityResult(Map<String, Boolean> result) { Log.e("ActivityResultLauncher", ""+result.toString() ); Boolean areAllGranted = true; for ( Boolean b : result.values() ) { areAllGranted = areAllGranted && b; } if ( areAllGranted ) Log.e( "ActivityResultLauncher","权限申请成功"); else Log.e( "ActivityResultLauncher", "权限申请失败"); } });
然后在getPermission()里调用:
activityResultLauncher.launch(new String[]{ Manifest.permission.BLUETOOTH_CONNECT });
但不管用哪种方式,请求权限的用户对话框都不显示,onPermissionRequestResult直接返回False(也就是拒绝)。LogCat里没任何错误信息(除了我自己加的日志),调试Android库代码也没发现异常。
更新
就在我发布这个问题的时候,我尝试清理了模拟器设备。
清理后第一次运行代码,应用直接崩溃,LogCat里捕获到以下信息:
Attempting to launch an unregistered ActivityResultLauncher with contract
androidx.activity.result.contract.ActivityResultContracts$RequestMultiplePermissions
and input [Ljava.lang.String. You must ensure the
ActivityResultLauncher is registered before calling launch().
我确实是在onCreate里注册的activityResultLauncher,搞不懂为什么提示未注册。而且这个错误只在清理设备文件后第一次运行时出现。
之后我再次启动应用(没改任何代码),这次正常运行,对话框显示了,我也能授予权限。
有人知道这到底是怎么回事吗?
问题分析与解决方案
- 首次启动崩溃原因:清理模拟器后首次启动时,广播可能在
onCreate执行完成前就被触发,此时activityResultLauncher还没完成注册,调用launch()就会抛出未注册的异常。 - 权限对话框不显示的潜在问题:
- 清理前的模拟器可能缓存了权限拒绝状态,系统直接返回拒绝而不弹出对话框;
- 广播接收器中使用的
thisActivity实例可能存在上下文问题,导致权限请求逻辑失效;
- 修复建议:
- 将
activityResultLauncher的注册代码放在onCreate方法最开头,确保在任何回调触发前完成注册; - 在广播接收器中增加判断:若
activityResultLauncher未初始化,通过Handler.postDelayed延迟1-2秒再处理权限请求; - 调整设置界面发送广播的时机,确保MainActivity完全启动后再发送Intent;
- 测试时直接在应用设置中清除数据,彻底重置权限状态,避免模拟器缓存干扰。
- 将
内容的提问来源于stack exchange,提问作者Jan Petersen

