因为项目需要,使用原生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,因为他们也确实不懂