已声明BLUETOOTH_CONNECT与BLUETOOTH_SCAN仍提示权限缺失求助
Android BLUETOOTH_CONNECT和BLUETOOTH_SCAN权限缺失问题排查
我遇到了BLUETOOTH_CONNECT和BLUETOOTH_SCAN权限的问题,但我已经在清单文件中进行了声明。
以下是完整的AndroidManifest.xml文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <!-- Request legacy Bluetooth permissions on older devices. --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Needed only if your app looks for Bluetooth devices. If your app doesn't use Bluetooth scan results to derive physical location information, you can strongly assert that your app doesn't derive physical location. --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- Needed only if your app makes the device discoverable to Bluetooth devices. --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <!-- Needed only if your app communicates with already-paired Bluetooth devices. --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Needed only if your app uses Bluetooth scan results to derive physical location. --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Include "neverForLocation" only if you can strongly assert that your app never derives physical location from Bluetooth scan results. --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- Not needed if you can strongly assert that your app never derives physical location from Bluetooth scan results and doesn't need location access for any other purpose. --> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-feature android:name="android.hardware.bluetooth" android:required="true"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> </manifest>
问题原因分析
重复权限声明冲突
你重复声明了BLUETOOTH_SCAN和BLUETOOTH_ADMIN:BLUETOOTH_SCAN一次无flag,一次带neverForLocation,系统无法识别正确配置;BLUETOOTH_ADMIN第二次声明未加maxSdkVersion="30",在高版本设备上造成冗余。
未处理动态权限申请
Android 12(API 31)及以上版本中,BLUETOOTH_SCAN、BLUETOOTH_CONNECT属于危险权限,仅在Manifest声明完全不够,必须在运行时主动请求用户授权。位置权限逻辑矛盾
你同时声明了ACCESS_FINE_LOCATION和BLUETOOTH_SCAN的neverForLocationflag,二者互斥:- 若App不需要通过蓝牙扫描获取位置,就不需要位置权限,只保留带
neverForLocation的BLUETOOTH_SCAN; - 若需要位置信息,就去掉
neverForLocationflag,并确保动态申请位置权限。
- 若App不需要通过蓝牙扫描获取位置,就不需要位置权限,只保留带
修正后的Manifest示例
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <!-- 适配API 30及以下的旧蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 12+ 蓝牙权限 --> <!-- 不需要蓝牙定位的情况,添加neverForLocation flag --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 仅当需要通过蓝牙获取位置时,才启用以下权限 --> <!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> --> <!-- <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="32" /> --> <uses-feature android:name="android.hardware.bluetooth" android:required="true"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> </manifest>
运行时权限申请代码示例(Kotlin)
private fun requestBluetoothPermissions() { val permissionsToRequest = mutableListOf<String>() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // 检查BLUETOOTH_SCAN权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { permissionsToRequest.add(Manifest.permission.BLUETOOTH_SCAN) } // 检查BLUETOOTH_CONNECT权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { permissionsToRequest.add(Manifest.permission.BLUETOOTH_CONNECT) } // 如果需要位置权限,取消注释下面代码 // if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION) // } } if (permissionsToRequest.isNotEmpty()) { ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(), 1001) } } // 权限申请结果回调 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 1001) { val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } if (allGranted) { // 权限全部授予,执行蓝牙相关操作 } else { // 权限被拒绝,提示用户前往设置开启 } } }
内容的提问来源于stack exchange,提问作者HyeRan Seo
相关产品推荐
相关产品推荐

