API29下Jetpack Compose应用蓝牙权限自动授予异常问题
问题分析与解决方案
核心原因
API29(Android 10)中,BLUETOOTH、BLUETOOTH_SCAN、BLUETOOTH_CONNECT这类蓝牙相关权限属于正常权限,系统会在应用安装时自动授予,不需要用户手动确认。所以你调用requestPermissions时不会弹出授权对话框,直接返回权限已授予的结果,这和日志里显示的true以及直接收到onRequestPermissionsResult回调的表现完全吻合。
而定位权限(如ACCESS_FINE_LOCATION)属于危险权限,必须弹出授权对话框让用户确认,这就是两者表现不同的根本原因。
代码适配建议
1. 分版本处理权限逻辑
从API31(Android 12)开始,BLUETOOTH_SCAN、BLUETOOTH_CONNECT才被列为危险权限,需要动态申请并弹出对话框。如果你的应用需要兼容多版本,可按以下方式处理:
Button(onClick = { val bluetoothPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT ) } else { arrayOf( Manifest.permission.BLUETOOTH ) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ActivityCompat.requestPermissions(activity, bluetoothPermissions, 3) } else { // API31以下无需申请,直接使用权限即可 Log.d("bluetooth permission", "权限已自动授予") // 执行蓝牙相关逻辑 } })
2. 优化权限回调判断
即使API29下会直接回调,也可以在onRequestPermissionsResult中增加结果校验,确保后续逻辑稳定:
@Deprecated("Deprecated in Java") override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 3) { val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } Log.d("permission", "bluetooth 权限状态:$allGranted") // 这里处理权限授予后的业务逻辑 } }
总结
- API29及以下版本,蓝牙权限为正常权限,安装即自动授予,不会触发授权对话框。
- 若需适配API31+版本,必须针对
BLUETOOTH_SCAN、BLUETOOTH_CONNECT做动态权限申请,此时才会弹出用户授权对话框。
内容的提问来源于stack exchange,提问作者Harvey Xie
相关产品推荐
相关产品推荐

