Android Studio API32下requestPermissions无权限弹窗问题
问题根因
- 核心错误:尝试直接申请
NEARBY_DEVICES权限组。Android系统不支持开发者直接申请权限组,权限组仅用于系统在设置页归类展示权限,只能申请组内的具体运行时权限,传入权限组发起申请会被系统直接拦截,不弹出任何提示 - Manifest文件存在语法错误:权限声明块末尾多了一行无标签包裹的纯文本
"android.permission-group.NEARBY_DEVICES",MainActivity节点多写了一个多余的>闭合尖括号,会导致Manifest解析异常,所有权限声明失效 - 权限申请逻辑不符合版本规则:Android 12(API 31)及以上版本中,旧版
BLUETOOTH、BLUETOOTH_ADMIN属于安装时自动授予的普通权限,不需要运行时申请;同时ACCESS_BACKGROUND_LOCATION后台位置权限从Android 10开始就不允许和其他前台权限一起申请,混合申请会被系统直接忽略 - 无效冗余:申请的权限列表中重复写入了两次
BLUETOOTH_CONNECT,属于无效写法
修复方案
1. 修正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" package="com.example.navigation" > <!-- Android 11及以下版本的旧蓝牙权限,高版本不需要 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android12+ 蓝牙运行时权限,不需要通过蓝牙推导位置的话加neverForLocation标记,可免除位置权限要求 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android11及以下扫描蓝牙需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30"/> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <!-- 移除NEARBY_DEVICES权限组的错误声明,移除孤立的纯文本行 --> <uses-feature android:name="android.hardware.bluetooth" android:required="false" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Navigation" tools:targetApi="32" > <activity android:name=".DeviceScanActivity" android:exported="false" /> <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" > <!-- 移除这里多余的>符号 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
2. 重写权限申请逻辑
按系统版本拆分需要申请的权限列表,分开申请前台权限和后台位置权限,移除重复、无效的权限项:
private static final int REQUEST_CODE_NEARBY_PERMS = 1; private static final int REQUEST_CODE_BACKGROUND_LOC = 2; public void getPermissions(){ List<String> needRequest = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android12+ 只需要申请新的蓝牙相关运行时权限 if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.BLUETOOTH_SCAN); } if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.BLUETOOTH_CONNECT); } if (checkSelfPermission(Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.BLUETOOTH_ADVERTISE); } if (checkSelfPermission(Manifest.permission.ACTIVITY_RECOGNITION) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.ACTIVITY_RECOGNITION); } } else { // Android11及以下只需要申请位置权限即可扫描蓝牙 if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.ACCESS_FINE_LOCATION); } if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { needRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION); } } if (!needRequest.isEmpty()) { requestPermissions(needRequest.toArray(new String[0]), REQUEST_CODE_NEARBY_PERMS); return; } // 等前面的前台权限全部授予后,再单独申请后台位置权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, REQUEST_CODE_BACKGROUND_LOC); } }
3. 调整调用时机
不要在Activity未完全进入前台时调用权限申请方法,比如不要直接在onCreate生命周期第一行调用,建议放在用户点击「扫描蓝牙设备」这类交互按钮的点击事件中触发,避免系统拦截权限弹窗。
内容的提问来源于stack exchange,提问作者Ali Abdullah
相关产品推荐
相关产品推荐

