未能在iOS Flutter上显示第二个弹出窗口以请求始终允许位置权限

arknldoa  于 2023-02-26  发布在  iOS
关注(0)|答案(1)|浏览(589)

我使用Geolocator实现了一个渐进式Location权限请求,因为我需要应用的后台位置,而AndroidiOS平台都要求仅在获得while in use权限后才能请求。问题是,虽然在Android上,一切都按预期工作,第二次我用Prominent Disclosure请求权限时,它打开了Location Permission屏幕,iOS上的未显示要求将权限更改为always allow的第二个弹出窗口,仅返回LocationPermission.whileInUse状态。已在运行iOS 12.5的iPhone6和运行iOS 16的模拟器上尝试,但未显示第二个系统弹出窗口。我以为第二次请求权限时会看到第二个系统弹出窗口,我错了吗?
这是控制台上的指纹

// at start
flutter: LocationBloc.getLocationPermission value is denied

// at first request system popup appears
flutter: LocationBloc._requestLocationPermission value is whileInUse

// at second request system popup doesn't appear
flutter: TrackingRepository.getLocationPermission() LocationPermission is: LocationPermission.whileInUse
flutter: TrackingBloc._getBackgroundLocationPermission value is whileInUse
flutter: TrackingRepository.requestLocationPermission() LocationPermission is: LocationPermission.whileInUse
flutter: TrackingBloc._requestLocationPermission value is whileInUse

这是用于请求权限的方法:

Future<String> requestLocationPermission() async {
    return await locationManager.checkPermission().then((value) async {
      late String permission;
      if (value != LocationPermission.always) {
        permission =
            await locationManager.requestPermission().then((value) async {
          print(
              'TrackingRepository.requestLocationPermission() LocationPermission is: $value');
          switch (value) {
            case LocationPermission.denied:
              return 'denied';
            case LocationPermission.deniedForever:
              return 'deniedForever';
            case LocationPermission.whileInUse:
              return 'whileInUse';
            case LocationPermission.always:
              return 'always';
            case LocationPermission.unableToDetermine:
              return 'unableToDetermine';
          }
        }).catchError((e) {
          print('TrackingRepository.requestLocationPermission() error: $e');
        });
      }
      return permission;
    });
  }

我已经设置了Deployment target: 12.4,在info.plist中添加了两个条目

<key>NSLocationWhenInUseUsageDescription</key>
<string>fixit needs you position to enable its functionalities</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>fixit needs your position to enable you to track your routes even when is in background</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>fixit needs your position to enable you to track your routes even when is in background</string>
<key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>location</string>
        <string>processing</string>
        <string>remote-notification</string>
    </array>

我还在Signing & Capabilities/Background Modes中添加了Location updates
这是位置流方法,用于区分AndroidiOS设置:

Stream<Position> startTracking() {
    _positionStreamController = new StreamController<Position>.broadcast();

    locationManager.checkPermission().then((value) async {
      if (value == LocationPermission.denied ||
          value == LocationPermission.deniedForever ||
          value == LocationPermission.whileInUse) {
        await locationManager.requestPermission().then((value) {
          print(
              'TrackingRepository.startTracking() requestPermission is: $value');
        }).catchError((e) {
          print(
              'TrackingRepository.startTracking() requestPermission error: $e');
        });
      }
    }).catchError((e) {
      print('TrackingRepository.startTracking() error: $e');
    });

    late var locationSettings = Platform.isIOS
        ? AppleSettings(
            accuracy: LocationAccuracy.bestForNavigation,
            allowBackgroundLocationUpdates: true,
            showBackgroundLocationIndicator: true,
            activityType: ActivityType.otherNavigation)
        : LocationSettings(accuracy: LocationAccuracy.best, distanceFilter: 0);

    _positionSubscription = locationManager
        .getPositionStream(locationSettings: locationSettings)
        .listen((event) {
      _positionStreamController.sink.add(event);
    });

    return _positionStreamController.stream;
  }

现在,当我在iPhone6和iOS12.5上试用它时,我在系统弹出窗口中只看到AcceptDeny选项,但我还希望有Always allow选项,所以我必须手动选择它,否则不会收到后台位置更新。难道不应该出现第二个系统弹出窗口以允许更改权限吗?
我错过了一些设置吗?非常感谢。

fcg9iug3

fcg9iug31#

经过多次尝试(都失败了)打开第二个系统弹出窗口请求always权限,我开始想,正如Paulw11所评论的,可能问题出在Geolocator所做的通用位置权限请求上,所以我决定试试permission_handler插件(只是为了iOS启动)它确实允许检查状态和请求特定的位置权限类型。它确实起作用了。现在它最终打开第二系统弹出窗口以便用户可以将许可改变为总是,在iOS上(在模拟器和我即将退休的iPhone6上)以及Android平台上。这个通用位置权限实际上可能是iOS不显示第二个系统弹出窗口的真正原因,即使使用permission_handler也是如此Permission.location.request()没有显示系统弹出窗口,而Permission.locationWhenInUse.request()显示。下面是工作代码:
位置

/// Using permission_handler for both platforms
  Future<String> getLocationPermission() async {
    print('\n\nLocationRepository.getLocationPermission() started\n\n');
    late String permission;
    permission = await Permission.locationWhenInUse.status.then((value) {
      print(
          '\n\n LocationRepository.getLocationPermission Permission.locationWhenInUse.status is ${value.name}');

      // permission = await Permission.location.status.then((value) {
      //   print(
      //       '\n\n LocationRepository.getLocationPermission Permission.location.status is ${value.name}');
      switch (value) {
        case PermissionStatus.denied:
          return 'denied';
        case PermissionStatus.permanentlyDenied:
          return 'deniedForever';
        case PermissionStatus.limited:
          return 'limited';
        case PermissionStatus.granted:
          return 'granted';
        case PermissionStatus.restricted:
          return 'restricted';
      }
    });
    return permission;
  }

  Future<String> requestLocationPermission() async {
    print('LocationRepository.requestLocationPermission started');
    late String permission;
    // general location doesn't open the popup
    // var status = await Permission.location.status;
    // print('Permission.location.status is $status');
    var status = await Permission.locationWhenInUse.status;
    print('Permission.locationWhenInUse.status is $status');

    /// NOT Granted
    if (!status.isGranted) {
      // var status = await Permission.location.request();
      // print('Permission.location.request() status is $status');
      var status = await Permission.locationWhenInUse.request();
      print('Permission.locationWhenInUse.request() status is $status');
      if (status.isGranted) {
        permission = 'granted';
      } else {
        permission = 'denied';
      }
    }

    /// Granted
    else {
      permission = 'granted';
    }
    return permission;
  }

Bg位置

/// Using permission_handler for both
  Future<String> getLocationPermissionStatus() async {
    print('\n\nTrackingRepository.getLocationPermissionStatus() started\n\n');
    late String permission;
    permission = await Permission.locationAlways.status.then((value) {
      print(
          'TrackingRepository.getLocationPermissionStatus() Permission.locationAlways.status is: ${value.name}\n\n');
      switch (value) {
        case PermissionStatus.denied:
          return 'denied';
        case PermissionStatus.permanentlyDenied:
          return 'deniedForever';
        case PermissionStatus.limited:
          return 'limited';
        case PermissionStatus.granted:
          return 'granted';
        case PermissionStatus.restricted:
          return 'restricted';
      }
    });
    return permission;
  }

  Future<String> requestLocationPermission() async {
    late String permission;
    var locationWhenInUseStatus =
        await Permission.locationWhenInUse.status.then((value) {
      print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
          'Permission.locationWhenInUse.status is: ${value.name}');
      return value;
    });

    /// locationWhenInUseStatus NOT Granted
    if (!locationWhenInUseStatus.isGranted) {
      print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
          'locationWhenInUseRequest NOT Granted, we now request it');

      /// Ask locationWhileInUse permission
      var locationWhenInUseRequest =
          await Permission.locationWhenInUse.request();
      print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
          'Permission.locationWhenInUse.request() status is: $locationWhenInUseRequest');

      /// locationWhenInUseRequest granted
      if (locationWhenInUseRequest.isGranted) {
        /// When in use NOW Granted
        print('\n\nTrackingRepository.requestLocationPermission() ios\n'
            'When in use NOW Granted');
        permission = 'whileInUse';
        PermissionStatus status = await Permission.locationAlways.request();
        print(
            '\n\nTrackingRepository.requestLocationPermission() ios locationWhenInUse is Now Granted\n'
            'Permission.locationAlways.request() status is: $status');

        if (status.isGranted) {
          /// Always is NOW Granted
          print('\n\nTrackingRepository.requestLocationPermission() ios\n'
              'Always use NOW Granted');
          permission = 'granted';
          print(
              '\n\nTrackingRepository.requestLocationPermission() ios locationAlways is Now Granted\n'
              'Permission.locationAlways.request() status is: $status');
        } else {
          //Do another stuff
        }
      }

      /// locationWhenInUseRequest not granted
      else {
        //The user deny the permission
        permission = 'denied';
      }
      if (locationWhenInUseRequest.isPermanentlyDenied) {
        //When the user previously rejected the permission and select never ask again
        //Open the screen of settings
        print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
            'Permission.locationWhenInUse.request is isPermanentlyDenied');
        permission = 'deniedForever';
        bool didOpen = await openAppSettings();
        print(
            '\n\nTrackingRepository.requestLocationPermission() ios isPermanentlyDenied\n'
            'openAppSettings() didOpen: $didOpen');

        // TODO: re-check for locationWhenInUse permission status?
      }
    }

    /// locationWhenInUseStatus is ALREADY Granted
    else {
      print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
          'locationWhenInUse ALREADY Granted, we now check for locationAlways permission');
      permission = 'whenInUse';

      var locationAlwaysStatus =
          await Permission.locationAlways.status.then((value) {
        print(
            '\n\nTrackingRepository.requestLocationPermission() iOS\nlocationWhenInUse already granted\n'
            'Permission.locationAlways.status is: ${value.name}');
        return value;
      });

      /// locationAlways is NOT Already Granted
      if (!locationAlwaysStatus.isGranted) {
        print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
            'locationAlways not granted, we now ask for permission');

        /// ask locationAlways permission
        var locationAlwaysStatus = await Permission.locationAlways.request();

        /// finally it opens the system popup
        print('\n\nTrackingRepository.requestLocationPermission() iOs\n'
            'Permission.locationAlways.request() status is: $locationAlwaysStatus');

        /// locationAlways is NOW Granted
        if (locationAlwaysStatus.isGranted) {
          print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
              'locationAlways was Granted upon request');
          permission = 'granted';
        }

        /// locationAlways was NOT Granted
        else {
          print('\n\nTrackingRepository.requestLocationPermission() iOS\n'
              'Permission.locationAlways.request() status was NOT Granted upon request, we now open AppSettings');
          await openAppSettings().then((value) {
            print(
                '\n\nTrackingRepository.requestLocationPermission() ios locationAlways isPermanentlyDenied\n'
                'openAppSettings() didOpen: $value');
          });
          // TODO: re-check locationAlways permission status??
        }
      }

      /// locationAlways is ALREADY Granted
      else {
        permission = 'granted';
      }
    }
    return permission;
  }

相关问题