【问题标题】:Flutter Geolocator not working on Android, but working perfectly on iOSFlutter Geolocator 无法在 Android 上运行,但可以在 iOS 上完美运行
【发布时间】:2024-08-17 22:50:02
【问题描述】:

我使用 Flutter 为 iOS 和 Android 平台构建了一个应用程序。它使用 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。问题是,根本没有为它生成错误日志,所以我没有明显的工作目标。终端中的一切似乎都运行良好。我已经做了一些试验和错误,看看我是否可以弄清楚这个过程在哪个阶段卡住了。这是我发现的:

  1. 该功能能够检查位置服务是否已启用,如果未启用,则会弹出警告。
  2. 该函数能够检查权限并在没有权限时通过弹出窗口请求权限(总是,仅在使用应用程序时,从不等)。如果选择从不,则会按预期生成警告。
  3. 如果权限被永久拒绝,该函数会发出警告。
  4. 当我们到达 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 模拟器交互有关。我会查看它们,如果我能解决,我会将其发布为我的查询的答案。

【问题讨论】:

    标签: android flutter android-studio build.gradle


    【解决方案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 连接,至于速度结果。

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

    【讨论】:

      最近更新 更多