iOS 接入flutter插件 permission_handler,定位权限始终获取不正确

因为项目需要,使用原生swift + flutter 的混编,因为项目涉及定位、导航功能,所以权限这部分不可能绕过,flutter 权限的插件以及版本号如下所示

permission_handler: ^11.4.0

各种配置(info.plis 文件、网络、flutter环境)这些都是确定没有任何问题的,但是位置获取权限始终都是

PermissionStatus.permanentlyDenied

因为接触flutter没多久,Android的小伙伴又是一点不懂iOS,一般认为Android上面没有问题,那么iOS上就肯定没有问题(说多了都是泪),一般这种混合开发的项目Android的话语权是比较重的,更多是倾向于敏捷,性能方面会稍微放松,一切为了先实现功能,从纯原声的角度出发,不论是Object-C 还是Swift,位置权限至少包含以下

永不
下次询问或共享时
使用App期间
始终

一直觉得是哪里配置错了,因为Android确实是可以的,可实在是找不到具体问题所在,只能采用最原始的方式,查一下flutter 的这个 permission_handler 插件
https://pub.dev/packages/permission_handler
依据经验,主要关注的肯定就是平台的差异化配置,结果发现如下信息

image.png

我们主要关注iOS的配置,结果发现少了最关键的第一步
Add the following to your Podfile file:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    target.build_configurations.each do |config|
      # You can remove unused permissions here
      # for more information: https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
      # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',

        ## dart: PermissionGroup.calendar
        'PERMISSION_EVENTS=1',
        
        ## dart: PermissionGroup.calendarFullAccess
        'PERMISSION_EVENTS_FULL_ACCESS=1',

        ## dart: PermissionGroup.reminders
        'PERMISSION_REMINDERS=1',

        ## dart: PermissionGroup.contacts
        'PERMISSION_CONTACTS=1',

        ## dart: PermissionGroup.camera
        'PERMISSION_CAMERA=1',

        ## dart: PermissionGroup.microphone
        'PERMISSION_MICROPHONE=1',

        ## dart: PermissionGroup.speech
        'PERMISSION_SPEECH_RECOGNIZER=1',

        ## dart: PermissionGroup.photos
        'PERMISSION_PHOTOS=1',

        ## The 'PERMISSION_LOCATION' macro enables the `locationWhenInUse` and `locationAlways` permission. If
        ## the application only requires `locationWhenInUse`, only specify the `PERMISSION_LOCATION_WHENINUSE`
        ## macro.
        ##
        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        'PERMISSION_LOCATION=1',
        'PERMISSION_LOCATION_WHENINUSE=0',

        ## dart: PermissionGroup.notification
        'PERMISSION_NOTIFICATIONS=1',

        ## dart: PermissionGroup.mediaLibrary
        'PERMISSION_MEDIA_LIBRARY=1',

        ## dart: PermissionGroup.sensors
        'PERMISSION_SENSORS=1',

        ## dart: PermissionGroup.bluetooth
        'PERMISSION_BLUETOOTH=1',

        ## dart: PermissionGroup.appTrackingTransparency
        'PERMISSION_APP_TRACKING_TRANSPARENCY=1',

        ## dart: PermissionGroup.criticalAlerts
        'PERMISSION_CRITICAL_ALERTS=1',

        ## dart: PermissionGroup.criticalAlerts
        'PERMISSION_ASSISTANT=1',
      ]

    end
  end
end

这个库权限相对来说比较全面,我们需要的是位置相关,主要查看如下所示部分

## The 'PERMISSION_LOCATION' macro enables the `locationWhenInUse` and `locationAlways` permission. If
        ## the application only requires `locationWhenInUse`, only specify the `PERMISSION_LOCATION_WHENINUSE`
        ## macro.
        ##
        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        'PERMISSION_LOCATION=1',
        'PERMISSION_LOCATION_WHENINUSE=0',

简单粗暴的理解为这样

  • PERMISSION_LOCATION 包含 (locationWhenInUse、locationAlways)
  • PERMISSION_LOCATION_WHENINUSE 仅仅包含(locationWhenInUse)
    这里建议使用 PERMISSION_LOCATION ,便于后期适应复杂业务场景,这里面还有其他的一些权限,感兴趣可以研究研究,也没有什么难度
    经过上述的配置,iOS 位置权限这部分也没啥问题了,至此,大功告成
    这里贴出一些可供参考的flutter代码片段,仅供小伙伴参考
  Future<void> _requestLocationPermission() async {
    // 检查当前权限状态
    var status = await Permission.location.status;
    if (status == PermissionStatus.denied) {
      // 首次申请"使用应用期间"权限
      status = await Permission.locationWhenInUse.request();
      if (status == PermissionStatus.granted) {
        // 成功获取"使用应用期间"权限
        print("已获取使用应用期间的定位权限");

        // 检查是否需要始终权限
        bool needAlwaysPermission = true; // 根据业务需求决定
        if (needAlwaysPermission) {
          await _requestAlwaysPermission();
        }
      } else if (status == PermissionStatus.permanentlyDenied) {
        // 永久拒绝,引导至设置
        print("用户拒绝了使用应用期间的定位权限");
        openAppSettings();
      }
    } else if (status == PermissionStatus.granted) {
      // 已有权限,检查是否为"始终允许"
      if (await Permission.locationAlways.isGranted) {
        print("已获取始终允许的定位权限");
      } else {
        // 只有"使用期间"权限,可选择是否请求"始终允许"
        await _requestAlwaysPermission();
      }
    } else if (status == PermissionStatus.permanentlyDenied) {
      // 永久拒绝,引导至设置
      openAppSettings();
    }
  }

  Future<void> _requestAlwaysPermission() async {
    // 请求"始终允许"权限
    var status = await Permission.locationAlways.request();
    if (status == PermissionStatus.granted) {
      print("成功获取始终允许的定位权限");
    } else {
      print("用户拒绝了始终允许的定位权限");
    }
  }

上面的 openAppSettings() 是跳转至iOS系统权限设置的,具体的业务可以根据上面不同权限类型去自行设置,比如:

  • 用户拒绝权限后可能需要给出一定的提示(一般就是个弹出框),引导用户去开启权限
  • 用户授权后可能会定位或者导航等等。。。

总结:

  • 不要迷信他人的决定,根据自身的经验,大胆验证自己的猜想
    • 跨行被指导一定要慎重,一定不要屈服,不然很容易背锅(我经常听到的一句话:你看看Android都没事,就你iOS有问题,基本都是因为flutter 的平台差异化配置导致)
  • 必要的时候一定要细看文档,特别是混合开发中的一些差异化配置,没有人有义务一定兼容iOS,因为他们也确实不懂
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容