Flutter Geolocator 无法在 Android 上运行,但可以在 iOS 上完美运行

Posted

技术标签:

【中文标题】Flutter Geolocator 无法在 Android 上运行,但可以在 iOS 上完美运行【英文标题】:Flutter Geolocator not working on Android, but working perfectly on iOS 【发布时间】:2021-12-07 15:45:33 【问题描述】:

我使用 Flutter 为 iosandroid 平台构建了一个应用程序。它使用 Geolocator 包,版本 7.7.0。奇怪的是,虽然它可以在 iOS 模拟器和物理设备上运行,但它在 Android 模拟器或物理设备上根本不起作用。这是我根据 pub.dev 的指导创建的基于地理定位器的异步函数,用于检查权限并获取用户的当前位置:

  _determineCurrentPositionStarting() async 
    bool serviceEnabled;
    LocationPermission permission;

    // Test if location services are enabled.
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) 
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      return Future.error('Location services are disabled.');
    

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) 
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) 
        // Permissions are denied, next time you could try
        // requesting permissions again (this is also where
        // Android's shouldShowRequestPermissionRationale
        // returned true. According to Android guidelines
        // your App should show an explanatory UI now.
        return Future.error('Location permissions are denied.');
      
    

    if (permission == LocationPermission.deniedForever) 
      // Permissions are denied forever, handle appropriately.
      return Future.error(
          'Location permissions are permanently denied, so we cannot request permissions.');
    

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    return await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.best,
      forceAndroidLocationManager: true,
    ).then((Position position) 
      setState(() 
        gcStartingLatitudeGEODEG.text = position.latitude.toStringAsFixed(6);
        gcStartingLongitudeGEODEG.text = position.longitude.toStringAsFixed(6);
      );
    ).catchError((e) 
      print(e);
    );
  

另外,调用上述函数的onPressed命令,在一个按钮中,如下所示:

        onPressed: () async 
          _determineCurrentPositionStarting();
        ,

在 iOS 上,它可以正常工作,获取用户的位置。它只是不适用于Android。问题是,根本没有为它生成错误日志,所以我没有明显的工作目标。终端中的一切似乎都运行良好。我已经做了一些试验和错误,看看我是否可以弄清楚这个过程在哪个阶段卡住了。这是我发现的:

    该功能能够检查位置服务是否已启用,如果未启用,则会弹出警告。 该函数能够检查权限并在没有权限时通过弹出窗口请求权限(总是,仅在使用应用程序时,从不等)。如果选择从不,则会按预期生成警告。 如果权限被永久拒绝,该函数会发出警告。 当我们到达 return await Geolocator.getCurrentPosition...

这让我觉得 android 平台和 await Geolocator.getCurrentPosition() 函数存在问题。

由于在我的 iOS 设备和模拟器上一切正常,但在 Android 上却不行,我认为这与 Android 特定设置有关。

据我所知,在我的 androidmanifest.xml 文件中,记录了正确的权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

我正在使用 gradle 版本 7.0.0,在我的 build.gradle 文件(android > app > build.gradle)中,我的 SDK 版本是:

compileSdkVersion: 31 minSdkVersion: 23 targetSdkVersion:31

如果有帮助,Flutter Doctor 没有错误:

[✓] Flutter (Channel stable, 2.5.3, on macOS 11.6 20G165 darwin-x64, locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] Connected device (2 available)

我有什么遗漏吗?有什么理由可以说明为什么它不能在 Android 上运行?任何帮助将不胜感激!

编辑

我刚刚在运行 Android 11.0 而不是 12.0 的 Android Emulator 上进行了尝试,它运行良好。这对我来说表明它可能与包版本 7.0.0 中的重大更改如何交互可能与 Android 12.0 模拟器交互有关。我会查看它们,如果我能解决,我会将其发布为我的查询的答案。

【问题讨论】:

【参考方案1】:

首先我修改了获取坐标的函数,基于7.0.0版插件作者描述的breaking changes,主要是权限部分。

  _determineCurrentPositionStarting() async 
    bool serviceEnabled;
    LocationPermission permission;

    // Test if location services are enabled.
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) 
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      return;
    

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) 
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.deniedForever) 
        // Permissions are denied forever, handle appropriately.
        return;
      
    

    if (permission == LocationPermission.denied) 
      // Permissions are denied, next time you could try
      // requesting permissions again (this is also where
      // Android's shouldShowRequestPermissionRationale
      // returned true. According to Android guidelines
      // your App should show an explanatory UI now.
      return;
    

    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.

    return await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.bestForNavigation,
      forceAndroidLocationManager: true,
      timeLimit: null,
    ).then((Position position) 
      setState(() 
        gcStartingLatitudeGEODEG.text = position.latitude.toStringAsFixed(6);
        gcStartingLongitudeGEODEG.text = position.longitude.toStringAsFixed(6);
      );
    ).catchError((e) 
      print(e);
    );
  

然后,我决定做一个计时测试,似乎基本上,即使对于我最初认为它不起作用的 Android 设备,它实际上也起作用了,只是延迟了很长时间。

例如,在我的 Android 物理设备三星 Galaxy A21s 上,它需要 48 秒到几分钟不等,但它确实返回了坐标。

因此,我只能假设它确实适用于所有平台,并且完全取决于设备的类型、其中的 GPS 模块的质量以及用户所在位置的 GPS 连接,至于速度结果。

这就是它没有导致错误日志的原因。它正在工作,只是需要一段时间。

【讨论】:

以上是关于Flutter Geolocator 无法在 Android 上运行,但可以在 iOS 上完美运行的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:Geolocator返回方法'compareTo'在null上被调用

无法从 Flutter 中的 Open Weather API 获取数据

Flutter Geolocator 显示方法 toDouble() 在 null 上被调用

Flutter Geolocator 和 Google Maps:显示静态位置

使用 geolocator 和 provider 以及 flutter_maps 获取位置

Flutter Geolocator给出错误的纬度和经度