因?yàn)轫?xiàng)目需要,使用原生swift + flutter 的混編,因?yàn)轫?xiàng)目涉及定位、導(dǎo)航功能,所以權(quán)限這部分不可能繞過(guò),flutter 權(quán)限的插件以及版本號(hào)如下所示
permission_handler: ^11.4.0
各種配置(info.plis 文件、網(wǎng)絡(luò)、flutter環(huán)境)這些都是確定沒(méi)有任何問(wèn)題的,但是位置獲取權(quán)限始終都是
PermissionStatus.permanentlyDenied
因?yàn)榻佑|flutter沒(méi)多久,Android的小伙伴又是一點(diǎn)不懂iOS,一般認(rèn)為Android上面沒(méi)有問(wèn)題,那么iOS上就肯定沒(méi)有問(wèn)題(說(shuō)多了都是淚),一般這種混合開(kāi)發(fā)的項(xiàng)目Android的話(huà)語(yǔ)權(quán)是比較重的,更多是傾向于敏捷,性能方面會(huì)稍微放松,一切為了先實(shí)現(xiàn)功能,從純?cè)暤慕嵌瘸霭l(fā),不論是Object-C 還是Swift,位置權(quán)限至少包含以下
永不
下次詢(xún)問(wèn)或共享時(shí)
使用App期間
始終
一直覺(jué)得是哪里配置錯(cuò)了,因?yàn)锳ndroid確實(shí)是可以的,可實(shí)在是找不到具體問(wèn)題所在,只能采用最原始的方式,查一下flutter 的這個(gè) permission_handler 插件
https://pub.dev/packages/permission_handler
依據(jù)經(jīng)驗(yàn),主要關(guān)注的肯定就是平臺(tái)的差異化配置,結(jié)果發(fā)現(xiàn)如下信息

我們主要關(guān)注iOS的配置,結(jié)果發(fā)現(xiàn)少了最關(guān)鍵的第一步
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
這個(gè)庫(kù)權(quán)限相對(duì)來(lái)說(shuō)比較全面,我們需要的是位置相關(guān),主要查看如下所示部分
## 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',
簡(jiǎn)單粗暴的理解為這樣
- PERMISSION_LOCATION 包含 (locationWhenInUse、locationAlways)
- PERMISSION_LOCATION_WHENINUSE 僅僅包含(locationWhenInUse)
這里建議使用 PERMISSION_LOCATION ,便于后期適應(yīng)復(fù)雜業(yè)務(wù)場(chǎng)景,這里面還有其他的一些權(quán)限,感興趣可以研究研究,也沒(méi)有什么難度
經(jīng)過(guò)上述的配置,iOS 位置權(quán)限這部分也沒(méi)啥問(wèn)題了,至此,大功告成
這里貼出一些可供參考的flutter代碼片段,僅供小伙伴參考
Future<void> _requestLocationPermission() async {
// 檢查當(dāng)前權(quán)限狀態(tài)
var status = await Permission.location.status;
if (status == PermissionStatus.denied) {
// 首次申請(qǐng)"使用應(yīng)用期間"權(quán)限
status = await Permission.locationWhenInUse.request();
if (status == PermissionStatus.granted) {
// 成功獲取"使用應(yīng)用期間"權(quán)限
print("已獲取使用應(yīng)用期間的定位權(quán)限");
// 檢查是否需要始終權(quán)限
bool needAlwaysPermission = true; // 根據(jù)業(yè)務(wù)需求決定
if (needAlwaysPermission) {
await _requestAlwaysPermission();
}
} else if (status == PermissionStatus.permanentlyDenied) {
// 永久拒絕,引導(dǎo)至設(shè)置
print("用戶(hù)拒絕了使用應(yīng)用期間的定位權(quán)限");
openAppSettings();
}
} else if (status == PermissionStatus.granted) {
// 已有權(quán)限,檢查是否為"始終允許"
if (await Permission.locationAlways.isGranted) {
print("已獲取始終允許的定位權(quán)限");
} else {
// 只有"使用期間"權(quán)限,可選擇是否請(qǐng)求"始終允許"
await _requestAlwaysPermission();
}
} else if (status == PermissionStatus.permanentlyDenied) {
// 永久拒絕,引導(dǎo)至設(shè)置
openAppSettings();
}
}
Future<void> _requestAlwaysPermission() async {
// 請(qǐng)求"始終允許"權(quán)限
var status = await Permission.locationAlways.request();
if (status == PermissionStatus.granted) {
print("成功獲取始終允許的定位權(quán)限");
} else {
print("用戶(hù)拒絕了始終允許的定位權(quán)限");
}
}
上面的 openAppSettings() 是跳轉(zhuǎn)至iOS系統(tǒng)權(quán)限設(shè)置的,具體的業(yè)務(wù)可以根據(jù)上面不同權(quán)限類(lèi)型去自行設(shè)置,比如:
- 用戶(hù)拒絕權(quán)限后可能需要給出一定的提示(一般就是個(gè)彈出框),引導(dǎo)用戶(hù)去開(kāi)啟權(quán)限
- 用戶(hù)授權(quán)后可能會(huì)定位或者導(dǎo)航等等。。。
總結(jié):
- 不要迷信他人的決定,根據(jù)自身的經(jīng)驗(yàn),大膽驗(yàn)證自己的猜想
- 跨行被指導(dǎo)一定要慎重,一定不要屈服,不然很容易背鍋(我經(jīng)常聽(tīng)到的一句話(huà):你看看Android都沒(méi)事,就你iOS有問(wèn)題,基本都是因?yàn)閒lutter 的平臺(tái)差異化配置導(dǎo)致)
- 必要的時(shí)候一定要細(xì)看文檔,特別是混合開(kāi)發(fā)中的一些差異化配置,沒(méi)有人有義務(wù)一定兼容iOS,因?yàn)樗麄円泊_實(shí)不懂