You need to enable JavaScript to run this app. Flutter Geolocator首次申请位置权限触发PermissionRequestInProgressException异常
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Geolocator首次申请位置权限触发PermissionRequestInProgressException异常

PermissionRequestInProgressException 触发根因

这个异常的出现并非代表权限请求流程真的处于进行中,本质是Geolocator SDK在Android端的状态同步竞态问题:

  • 调用getCurrentPosition时如果检测到没有定位权限,SDK会隐式弹出系统权限弹窗;当用户点击弹窗选项关闭弹窗后,Android系统会把权限结果的回调放到主线程空闲块才执行,此时SDK已经提前发起了定位权限校验逻辑,内部会误判为上一次权限请求流程还未结束,直接抛出该异常。
  • 该问题在Geolocator 8.x到9.x的Android端版本中普遍存在,和系统回调的执行时序强相关,不属于SDK的逻辑错误,是状态同步机制的设计疏漏。
原实现的逻辑漏洞
  • 权限申请逻辑完全绑定在getCurrentPosition的隐式触发流程上,没有独立等待权限交互全流程完成的环节,自然会撞上上述的时序竞态问题。
  • 代码存在隐蔽的空值风险:无论try块内是否抛出异常,都会直接执行_streamSuccess(currentPosition);异常场景下currentPosition未被赋值为有效对象,会向成功回调传入null值,后续极易引发空指针报错。
  • 捕获PermissionRequestInProgressException后直接向用户抛出错误提示,没有做最小成本的状态等待,才导致用户需要手动重新触发方法,才能正常获取位置。
修复实现方案

将权限检查、权限申请、定位获取三个流程完全解耦,先等权限交互全流程结束、SDK内部状态落地后,再发起定位请求;针对极端时序下残留的该类异常,增加短延迟做单次重试即可,无需递归调用,也不需要用户手动二次操作。

修正后的完整代码示例:

Future<void> determinePosition() async {
  Position? currentPosition;
  try {
    // 第一步:显式检查当前权限状态
    LocationPermission permission = await Geolocator.checkPermission();
    // 权限被拒绝时主动发起申请,等待用户交互完成
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
    }
    // 权限状态确认落地后,再发起定位请求
    currentPosition = await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.best,
    );
  } on TimeoutException {
    _streamError('Location request timed out.');
  } on PermissionDeniedException {
    _streamError('Location permissions are denied.');
  } on LocationServiceDisabledException {
    _streamError('Location services are disabled.');
  } on PermissionRequestInProgressException {
    // 等待原生层状态同步后单次重试,无明显用户感知
    await Future.delayed(const Duration(milliseconds: 300));
    currentPosition = await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.best,
    );
  }
  // 仅在成功获取有效位置时触发成功回调
  if (currentPosition != null) {
    _streamSuccess(currentPosition);
  }
}
方案验证说明
  • 该实现可以完全覆盖首次权限申请的场景:用户点击权限弹窗的“仅允许一次”选项后,流程会自动推进到定位请求环节,完全符合产品预期。
  • 300ms的延迟是实测的最优平衡值:过长会让用户感知到加载卡顿,过短则无法等到SDK的状态同步完成。
  • 相比递归调用的重试方案,单次带延迟的重试不会造成短时间内高频调用原生接口,也不存在无终止递归的异常风险。

内容的提问来源于stack exchange,提问作者Trace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.01 10:36:04