Flutter使用permission_handler时附近设备权限不生效如何解决
问题根因
当前配置存在两处核心错误,导致蓝牙相关权限无法正常弹出申请、扫描功能失效:
- AndroidManifest.xml 未声明蓝牙扫描/连接所需的对应权限,系统根本不会向用户弹出蓝牙相关权限申请弹窗
- 权限校验逻辑仅申请了定位权限,完全没有覆盖Android 12及以上版本要求的专属蓝牙权限,手动进设置开权限后能用就是这个原因
修复步骤
1. 补全AndroidManifest.xml权限声明
在清单文件的<manifest>节点下,和现有通讯录、存储权限同级的位置,添加以下蓝牙相关权限配置:
<!-- Android 12+ 蓝牙扫描权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- Android 12+ 蓝牙连接权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android 11及以下版本兼容的旧版蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 11及以下版本蓝牙扫描所需的精确定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
注意:如果你的应用需要通过蓝牙扫描获取位置信息(如室内定位场景),请删除BLUETOOTH_SCAN权限下的android:usesPermissionFlags="neverForLocation"配置,否则扫描功能会抛出异常。
2. 替换原有权限校验逻辑
不要只校验定位权限,需要根据系统版本区分申请对应权限,替换原有权限判断代码即可:
bool permGranted = true; // 判断当前设备Android版本 final androidInfo = await DeviceInfoPlugin().androidInfo; final sdkInt = androidInfo.version.sdkInt; if (sdkInt >= 31) { // Android 12及以上校验蓝牙专属权限 // 校验扫描权限 final scanStatus = await Permission.bluetoothScan.status; if (scanStatus.isDenied) { permGranted = false; if (await Permission.bluetoothScan.request().isGranted) { permGranted = true; } } // 校验连接权限 final connectStatus = await Permission.bluetoothConnect.status; if (connectStatus.isDenied) { permGranted = false; if (await Permission.bluetoothConnect.request().isGranted) { permGranted = true; } } } else { // Android 11及以下校验定位权限 final locationStatus = await Permission.location.status; if (locationStatus.isDenied) { permGranted = false; if (await Permission.location.request().isGranted) { permGranted = true; } } } // 处理权限永久拒绝的场景 if (!permGranted) { if (sdkInt >=31) { if (await Permission.bluetoothScan.isPermanentlyDenied || await Permission.bluetoothConnect.isPermanentlyDenied) { // 弹窗提示用户需要到设置页开启权限,之后调用openAppSettings()跳转 } } else { if (await Permission.location.isPermanentlyDenied) { // 同上,引导用户手动开权限 } } } // 所有权限校验通过后再启动蓝牙扫描 if (permGranted) { _logMessage('Start ble discovery'); // 原有蓝牙扫描业务逻辑 }
补充:代码中用到的DeviceInfoPlugin来自device_info_plus插件,用于获取设备系统版本,在pubspec.yaml中添加对应依赖即可使用;openAppSettings()方法是permission_handler自带的方法,可直接调用跳转应用设置页。
内容的提问来源于stack exchange,提问作者Zipper
相关产品推荐
相关产品推荐

