You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter locationWhenInUse权限首次请求挂起二次运行正常问题

Flutter位置权限首次请求挂起问题排查与解决方案

基础环境信息

  • Flutter版本:2.10.5
  • pubspec.yaml 引入依赖版本:
google_maps_flutter: ^2.0.6
geolocator: ^8.2.1
geocoding: ^2.0.0  
permission_handler: ^9.2.0
  • Android端AndroidManifest.xml已配置权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

异常现象

  • 首次安装启动应用,代码执行到await Permission.locationWhenInUse.request()时直接挂起,后续无任何日志输出
  • 不卸载应用二次启动时,可正常识别已授权状态,输出have while in use access日志,证明首次授权操作实际已生效,但权限请求的回调未触发
  • 首次启动控制台仅输出如下提示:
Accessing hidden method Landroid/content/ContextWrapper;->getDisplay()Landroid/view/Display; (light greylist, linking)

根因排查思路

  • 依赖混用冲突:代码中同时使用permission_handler和未在pubspec中声明的Location类(来自location插件),两个权限处理插件同时注册位置权限监听、抢占系统权限请求回调通道,是首次请求无返回的核心原因。
  • 异步调用写法不规范:混用await+.then()的链式调用写法,在系统权限弹窗弹出时,Flutter异步事件循环的回调链路被打断,导致权限结果返回时无法命中提前注册的.then()回调。
  • permission_handler 9.x版本兼容问题:该版本在Android 12+设备上,未配置后台位置权限的场景下请求前台位置权限,存在已知的回调丢失bug。
  • 控制台输出的hidden method提示为Android系统非限制级灰名单API访问警告,和权限请求挂起无直接关联,可直接忽略。

修复方案

第一步:清理冗余依赖

删除代码中未声明的location插件相关调用,位置服务状态检查、权限请求逻辑统一使用permission_handler实现,避免多插件抢占回调通道。

第二步:重构权限请求代码

统一使用async/await语法编写异步逻辑,不要混用await和.then(),参考实现如下:

Future<void> _checkMapAuthentication() async {
  // 检查位置服务开关状态
  final ServiceStatus serviceStatus = await Permission.location.serviceStatus;
  print("Location service status -> $serviceStatus");

  // 位置服务未开启时引导用户开启
  if (serviceStatus == ServiceStatus.disabled) {
    final bool serviceOpened = await Permission.location.requestService();
    if (!serviceOpened) {
      print("Location service not enabled by user");
      return;
    }
  }

  // 检查使用时位置权限状态
  final PermissionStatus permissionStatus = await Permission.locationWhenInUse.status;
  print("Location when in use permission status -> $permissionStatus");

  if (permissionStatus == PermissionStatus.granted) {
    print("Have while in use location access");
    return;
  }

  // 请求使用时位置权限
  final PermissionStatus requestResult = await Permission.locationWhenInUse.request();
  if (requestResult.isDenied) {
    print("While in use location access denied");
    // 权限永久被拒时跳转系统设置页
    if (await Permission.locationWhenInUse.isPermanentlyDenied) {
      await openAppSettings();
    }
    return;
  }
  print("Got while in use location access");
}

第三步:补全Android端兼容配置

在app模块的build.gradle中将compileSdkVersion配置为31及以上,匹配permission_handler 9.x版本的编译要求:

android {
    compileSdkVersion 33 // 最低不可低于31
    // 其余原有配置保持不变
}

如果业务不需要后台定位能力,在AndroidManifest.xml的<application>标签内添加如下配置,移除permission_handler构建时默认合并的后台位置权限,避免Android 12+版本的兼容问题:

<application
  ...>
  <!-- 移除不需要的后台位置权限,避免前台权限请求受影响 -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" />
  <!-- 其余原有组件配置保持不变 -->
</application>

注意添加上述配置后,需要在Manifest根标签中声明tools命名空间:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="你的应用包名">

第四步:清理构建缓存验证

执行如下命令清理构建缓存后重新运行即可:

flutter clean
flutter pub get
flutter run

修复后首次安装启动时,位置权限弹窗弹出后无论用户选择允许或拒绝,都可以正常收到回调,不会再出现挂起无响应的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:09:41