Flutter集成华为定位 位置权限被拒时应用崩溃如何修复
问题描述
在华为设备上实现设备位置获取功能时,位置权限授予场景下功能运行正常,但用户拒绝位置权限后应用直接崩溃,相同逻辑使用谷歌定位服务时从未出现该问题。拒绝位置权限时控制台输出了QR扫码插件相关的报错,和位置功能逻辑无直接关联。
现有实现代码
Future<Location?> getAccuratePositionH() async { PermissionHandler permissionHandler = PermissionHandler(); bool status = await permissionHandler.requestLocationPermission(); if (status) { FusedLocationProviderClient locationService = FusedLocationProviderClient(); Location location = await locationService.getLastLocation(); return location; } else { return null; } }
报错信息
控制台日志
I/cgr.qrmv.QrMobVisPlugin( 5178): Permissions request denied. W/cgr.qrmv.QrMobVisPlugin( 5178): Starting QR Mobile Vision failed W/cgr.qrmv.QrMobVisPlugin( 5178): com.github.rmtmckenzie.qrmobilevision.QrReader$Exception: QR reader failed because noPermissions
异常堆栈
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=1, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.lea24.partyfinder/com.lea24.partyfinder.MainActivity}: java.lang.NullPointerException: Attempt to read from field 'io.flutter.plugin.common.MethodChannel$Result com.github.rmtmckenzie.qrmobilevision.QrMobileVisionPlugin$ReadingInstance.startResult' on a null object reference
问题根因
- 核心原因是权限请求码冲突:项目引入的
qrmobilevision扫码插件内部默认使用1作为权限请求码,你当前实现的位置权限申请逻辑也默认使用了1作为请求码。华为系统返回权限申请结果时,会把结果派发给所有监听权限回调的插件,扫码插件收到和自己请求码一致的回调后,误以为是自己发起的相机权限申请被拒绝,此时扫码插件并未启动、内部ReadingInstance实例为空,直接读取实例字段就触发了空指针崩溃。 - 谷歌定位服务未触发该问题,是因为GMS定位服务的权限请求逻辑使用了独立的专属请求码,不会和扫码插件的默认请求码重合,不会触发跨插件的回调误处理。
修复方案
- 修改位置权限请求的自定义请求码,不要使用默认值
1,替换为不与其他插件冲突的数值(比如20240901),从根源避免请求码撞车。 - 给定位逻辑补充异常捕获,就算定位服务本身调用出错,也不会抛出未捕获异常导致应用崩溃。
- 可选操作:升级
qrmobilevision插件到最新版本,新版本已经对权限回调时实例为空的场景做了空安全防护,就算出现请求码冲突也不会直接崩溃。
修复后的参考代码:
Future<Location?> getAccuratePositionH() async { PermissionHandler permissionHandler = PermissionHandler(); // 指定独立的权限请求码,避开其他插件使用的默认值1 bool status = await permissionHandler.requestLocationPermission(requestCode: 20240901); if (status) { try { FusedLocationProviderClient locationService = FusedLocationProviderClient(); Location location = await locationService.getLastLocation(); return location; } catch (e) { // 定位获取失败时统一返回null,不向外抛出异常 return null; } } else { return null; } }
内容的提问来源于stack exchange,提问作者Karol Wiśniewski
相关产品推荐
相关产品推荐

