如何在android 10或更高版本中获得flutter位置的“始终”许可? API 29 以上?

问题描述

我正在为我的一个颤振项目使用 Geolocator 包,并且我想在周期性的时间周期内获取我的当前位置。 为了获得许可,我编辑了 AndroidManifest.xml 并添加了这些行:

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

一切正常,但是当我在其中一部 android 10 手机中使用 apk 时,一切都向南! 首先,每当我第一次检查应用程序的许可状态时

 await Geolocator.checkPermission();

它在android 9中返回.denied,在android 10中返回.deniedForever,当检查权限时,android权限寻求弹出窗口出现,在android 9或以下版本中,允许按钮将权限设置为.always 但在 android 10 中设置为 .whileInUse,我在设置中找不到任何选项以手动将其设置为 .always。 经过一番研究,我了解到,我必须添加

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

添加了它们,但 android 10 仍然不像 android 9,仍然缺少应用程序管理器中的“始终”选项! 我遇到的主要问题是,每当我离开屏幕时,Geolocator.getCurrentPosition() 就会停止工作,但相同的代码在 android 9 中完美运行。

模拟 -

class _MyHomePageState extends State<MyHomePage> {
  List _loc = [];
  bool _isSwitchon = false;
  int _sec = 0;
  String _permissonStatus = "";

  Future _incrementCounter() async {
    Timer.periodic(Duration(seconds: 1),(timer) async {
      setState(() {
        _sec++;
      });
      if (_isSwitchon == false) {
        timer.cancel();
        setState(() {});
      } else if (_isSwitchon == true) {
        Position currentPosition = await Geolocator.getCurrentPosition();
        setState(() {
          _loc.add(currentPosition.toString());
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),),body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
            Text("Time Elapsed"),Text(_sec.toString() + "  sec"),Text(
              'current Location',Container(
              height: 300,child: ListView.builder(
                itemCount: _loc.length,itemBuilder: (BuildContext context,int i) {
                  return Text(
                    _loc[i],);
                },Row(
              children: [
                Expanded(
                  child: Container(),Column(
                  children: [
                    FloatingActionButton(
                      onpressed: () {
                        setState(() {
                          _isSwitchon = true;
                        });
                        _incrementCounter();
                      },child: Icon(Icons.play_arrow),Text("Start")
                  ],SizedBox(
                  width: 50,Column(
                  children: [
                    FloatingActionButton(
                      onpressed: () {
                        setState(() {
                          _isSwitchon = false;
                        });
                      },child: Icon(Icons.cancel),Text("Stop")
                  ],Expanded(
                  child: Container(),)
              ],Text(_permissonStatus),Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
                Column(
                  children: [
                    FloatingActionButton(
                      onpressed: () async {
                        await Geolocator.checkPermission().then((value) =>
                            setState(
                                () => _permissonStatus = value.toString()));
                      },child: Icon(Icons
                          .signal_wifi_statusbar_connected_no_internet_4_sharp),Text("status")
                  ],Column(
                  children: [
                    FloatingActionButton(
                      onpressed: () {
                        setState(() {
                          _loc = [];
                        });
                      },tooltip: 'Increment',child: Icon(Icons.add),Text("clear Location")
                  ],Column(
                  children: [
                    FloatingActionButton(
                      onpressed: () async {
                        await Geolocator.requestPermission();
                      },child: Icon(Icons.gps_fixed),Text("Permission Seeking")
                  ],],)
          ],);
  }
}

我的清单中的场景 -

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gps_test">
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/> 
   <application

   

解决方法

你说的是 android 10,我不明白为什么没有正确的按钮,但为了将来证明这种方法已经过时了。

Android docs

在 Android 11(API 级别 30)及更高版本上,系统对话框 不包括始终允许选项。相反,用户必须 在设置页面上启用后台位置,[...]。

您应该能够通过 .openLocationSettings().openAppSettings() 使用此 package 打开权限设置,然后用户必须导航到权限。