一瞒渠、前言
大數(shù)據(jù)時代皮璧,用戶對自己的隱私安全越來越關(guān)注,所以遥巴,隨著iOS系統(tǒng)更新千康,蘋果對用戶隱私相關(guān)(定位、相冊铲掐、網(wǎng)絡(luò)吧秕、粘貼板等)權(quán)限控制持續(xù)升級。其中定位權(quán)限相關(guān)申請API與配置項較多迹炼,本文旨在記錄說明 iOS8.0 - 14.0beta 從權(quán)限申請到獲取定位數(shù)據(jù)流程砸彬。
內(nèi)容包括定位權(quán)限、獲取定位數(shù)據(jù)斯入、定位權(quán)限API調(diào)用實踐砂碉。定位權(quán)限模塊按照系統(tǒng)相關(guān)性分別介紹該系統(tǒng)下權(quán)限配置與API調(diào)用細(xì)節(jié)、注意事項與表格總結(jié)刻两;獲取定位數(shù)據(jù)模塊介紹定位關(guān)鍵參數(shù)增蹭、單次/連續(xù)定位等;調(diào)用實踐模塊介紹了從 iOS8.0 - 14.0beta 系統(tǒng)定位權(quán)限的適配實踐磅摹。
二滋迈、定位權(quán)限
1、iOS8.*
-前臺定位
-需要在info.plist配置NSLocationWhenInUseUsageDescription字段户誓;
-首次使用定位時饼灿,通過API接口requestWhenInUseAuthorization申請應(yīng)用使用時權(quán)限;
注意:此權(quán)限下帝美,如果Xcode勾選 Capabilities -> UIBackgroundModes > Location updates碍彭,則app退到后臺仍可獲取定位數(shù)據(jù),但此時在手機(jī)上方會有定位小藍(lán)條提示悼潭;
-后臺定位
-需要在info.plist配置NSLocationAlwaysUsageDescription字段庇忌;
-需要Xcode勾選 Capabilities -> UIBackgroundModes > Location updates;
-首次使用定位時舰褪,通過API接口requestAlwaysAuthorization申請應(yīng)用未使用時權(quán)限皆疹;
2、iOS9.與iOS10.
-****前臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription字段占拍;
-首次使用定位時略就,通過API接口requestWhenInUseAuthorization申請應(yīng)用使用時權(quán)限捎迫,如下圖;
注意:此權(quán)限下残制,如果Xcode勾選 Capabilities -> UIBackgroundModes > Location updates并且allowsBackgroundLocationUpdates設(shè)為YES立砸,則app退到后臺仍可獲取定位數(shù)據(jù),但此時在手機(jī)上方會有定位小藍(lán)條提示初茶;
-****后臺定位****
-需要在info.plist配置NSLocationAlwaysUsageDescription字段颗祝;
-需要Xcode勾選 Capabilities -> UIBackgroundModes > Location updates;
-需要CLLocationManager設(shè)置allowsBackgroundLocationUpdates為YES恼布;
-首次使用定位時螺戳,通過API接口requestAlwaysAuthorization申請應(yīng)用未使用時權(quán)限,如下圖折汞;
-與iOS8.版本相比不同點***
-iOS9.后臺增加了allowsBackgroundLocationUpdates屬性倔幼,可以認(rèn)為在iOS8.下allowsBackgroundLocationUpdates永遠(yuǎn)為YES;
3爽待、iOS11.與iOS12.
-****前臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription字段损同;
-首次使用定位時,通過API接口requestWhenInUseAuthorization申請應(yīng)用使用時權(quán)限鸟款,如下圖膏燃;
注意:此權(quán)限下,如果Xcode勾選 Capabilities -> UIBackgroundModes > Location updates并且allowsBackgroundLocationUpdates設(shè)為YES何什,則app退到后臺仍可獲取定位數(shù)據(jù)组哩,但此時在手機(jī)上方會有定位小藍(lán)條提示,此小藍(lán)條不可隱藏处渣;
-****后臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription伶贰、NSLocationAlwaysAndWhenInUseUsageDescription字段;
-需要Xcode勾選 Capabilities -> UIBackgroundModes > Location updates罐栈;
-需要CLLocationManager設(shè)置allowsBackgroundLocationUpdates為YES黍衙;
-首次使用定位時,通過API接口requestAlwaysAuthorization申請應(yīng)用未使用時權(quán)限悠瞬,如下圖们豌;
注意:此權(quán)限下,當(dāng)app在后臺時浅妆,系統(tǒng)默認(rèn)不展示定位小藍(lán)條,可通過showsBackgroundLocationIndicator控制小藍(lán)條是否顯示障癌;
-與iOS10.版本相比不同點***
-iOS11.*變更了后臺定位權(quán)限配置字段凌外;
-iOS11.*以后如果申請后臺定位,info.plist需要同時配置NSLocationWhenInUseUsageDescription涛浙、NSLocationAlwaysAndWhenInUseUsageDescription兩個字段康辑;
-iOS11.增加了showsBackgroundLocationIndicator屬性摄欲,當(dāng)擁有后臺定位權(quán)限時,用于控制定位小藍(lán)條是否顯示疮薇⌒厍剑可以認(rèn)為在iOS10.之前showsBackgroundLocationIndicator永遠(yuǎn)為NO;
4按咒、iOS13.*
-****前臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription字段迟隅;
-首次使用定位時,通過API接口requestWhenInUseAuthorization申請應(yīng)用使用時權(quán)限励七;
注意:權(quán)限申請彈窗與之前版本不一致智袭,新增了允許一次選項;如果用戶選擇允許一次后掠抬,下次在使用app時吼野,仍可重新調(diào)用API申請定位權(quán)限;如下圖
-****后臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription两波、NSLocationAlwaysAndWhenInUseUsageDescription字段瞳步;
-需要Xcode勾選 Capabilities -> UIBackgroundModes > Location updates;
-需要CLLocationManager設(shè)置allowsBackgroundLocationUpdates為YES腰奋;
-首次使用定位時单起,通過API接口requestAlwaysAuthorization申請權(quán)限;
注意:1)直接調(diào)用requestAlwaysAuthorization申請權(quán)限時氛堕,權(quán)限彈窗與調(diào)用requestWhenInUseAuthorization一樣馏臭,如上圖,用戶只可以選擇應(yīng)用使用時或者只允許一次讼稚。不同點:當(dāng)選擇使用app時允許選項后括儒,狀態(tài)變更的回調(diào)為kCLAuthorizationStatusAuthorizedAlways;并且當(dāng)app退到后臺后锐想,系統(tǒng)會擇機(jī)彈窗提示用戶是否要升級權(quán)限為始終允許帮寻。如下圖:
2)如果想要在應(yīng)用使用期間彈窗申請始終允許,則需要先調(diào)用requestWhenInUseAuthorization赠摇,并且獲得應(yīng)用使用期間定位權(quán)限固逗,之后在調(diào)用requestAlwaysAuthorization則可彈窗申請始終允許,如下圖藕帜;(感覺不是太友好烫罩,不建議使用)
-與iOS12.版本相比不同點***
-使用應(yīng)用期間的定位權(quán)限增加了允許一次選項;
-不能直接申請后臺定位權(quán)限洽故,需要用戶先選擇應(yīng)用使用期間的定位權(quán)限后贝攒,在進(jìn)行權(quán)限升級;
5时甚、iOS14.*(beta版本)
-****前臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription字段隘弊;
-首次使用定位時哈踱,通過API接口requestWhenInUseAuthorization申請應(yīng)用使用時權(quán)限;
注意:權(quán)限申請彈窗與之前版本不一致梨熙,新增了精確位置開關(guān)开镣,新增了小地圖展示當(dāng)前位置;小地圖的顯示咽扇,支持在手機(jī)定位設(shè)置中選擇邪财,如果選擇關(guān)閉不顯示則手機(jī)中所有app都不顯示此小地圖。如下圖
-****后臺定位****
-需要在info.plist配置NSLocationWhenInUseUsageDescription肌割、NSLocationAlwaysAndWhenInUseUsageDescription字段卧蜓;
-需要Xcode勾選 Capabilities -> UIBackgroundModes > Location updates;
-需要CLLocationManager設(shè)置allowsBackgroundLocationUpdates為YES把敞;
-首次使用定位時弥奸,通過API接口requestAlwaysAuthorization申請權(quán)限;
-****新增精度權(quán)限****
-需要在info.plist配置NSLocationTemporaryUsageDescriptionDictionary奋早,如下:
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
ExampleUsageDescription
This app needs accurate location so it can verify that you are in a supported region.
AnotherUsageDescription
This app needs accurate location so it can show you relevant results.
</dict>
-新增屬性字段@property (nonatomic, readonly) CLAccuracyAuthorization accuracyAuthorization API_AVAILABLE(ios(14.0), macos(11.0), watchos(7.0), tvos(14.0))盛霎;可以獲取當(dāng)前的定位精度權(quán)限。
-在app已經(jīng)獲得定位權(quán)限之后耽装,并且當(dāng)前用戶選擇的是模糊定位愤炸,則允許應(yīng)用申請一次臨時精確定位權(quán)限,申請api為- (void)requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(NSString )purposeKey completion:(void(^)(NSError ))completion; 其中purposeKey既為plist中配置字典中的key掉奄,可以有多個规个,對應(yīng)app中不同的定位需求場景;注意:**此API不能用于申請定位權(quán)限姓建,只能用于從模糊定位升級為精確定位诞仓;申請定位權(quán)限只能調(diào)用requestWhen或requestAlways,如果沒有獲得定位權(quán)限速兔,直接調(diào)用此API無效墅拭。如下圖
-如果app默認(rèn)不使用精確定位,則可以在info.plist中配置NSLocationDefaultAccuracyReduced字段涣狗,配置該字段后谍婉,申請定位權(quán)限的小地圖中不在有精確定位的開關(guān),即為關(guān)镀钓。如下面圖示
-需要注意該字段類型為Boolean穗熬,如果為其他類型則不起效;
-配置該字段后丁溅,申請定位權(quán)限的小地圖左上角則沒有精確開關(guān)死陆,默認(rèn)關(guān)閉,如下面圖示唧瘾。但是如果info.plist中配置了NSLocationTemporaryUsageDescriptionDictionary措译,則仍可以申請臨時的精確定位權(quán)限;
-??:測試期間使用Xcode12 beta1到beta4饰序,直接使用info.plist的Property List添加NSLocationDefaultAccuracyReduced字段只能是string领虹,所以會造成不起效的問題,如果您也遇到類似問題求豫,可以點擊info.plist右鍵Open As -> Source Code塌衰,即使用源碼直接添加既可起效;
<key>NSLocationDefaultAccuracyReduced</key>
<true/>
[圖片上傳失敗...(image-24baae-1637218463749)]
-與iOS13.版本相比不同點***
-權(quán)限申請彈窗與之前版本不一致蝠嘉;
-新增精度權(quán)限相關(guān)plist設(shè)置最疆、授權(quán)、讀仍楦妗努酸;
-新增臨時一次從模糊定位升級精確定位API;
-新增定位權(quán)限變更回調(diào)杜恰;
6获诈、定位權(quán)限更新回調(diào)
-****iOS13.*及以前:****- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
-如主動獲取定位權(quán)限可使用類方法:+ (CLAuthorizationStatus)authorizationStatus心褐;
-CLAuthorizationStatus枚舉取值
typedef NS_ENUM(int, CLAuthorizationStatus) {
kCLAuthorizationStatusNotDetermined = 0, //用戶沒有決定是否使用定位服務(wù)
kCLAuthorizationStatusRestricted, //定位服務(wù)授權(quán)狀態(tài)受限制
kCLAuthorizationStatusDenied, //用戶拒絕/定位總開關(guān)關(guān)閉
kCLAuthorizationStatusAuthorizedAlways, //始終允許
kCLAuthorizationStatusAuthorizedWhenInUse, //在應(yīng)用使用期間
kCLAuthorizationStatusAuthorized //已經(jīng)廢棄舔涎,等同于始終允許
};
-iOS14.及以后***:- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager;
-通過manager.authorizationStatus對象方法獲取當(dāng)前定位權(quán)限逗爹,此方法在iOS13及以前版本是類方法亡嫌;
-通過manager.accuracyAuthorization對象方法獲取當(dāng)前精度權(quán)限;
-CLAccuracyAuthorization枚舉取值
typedef NS_ENUM(NSInteger, CLAccuracyAuthorization) {
CLAccuracyAuthorizationFullAccuracy, //精確定位
CLAccuracyAuthorizationReducedAccuracy, //模糊定位
};
7掘而、總結(jié)
-****定位權(quán)限注意事項****
-iOS11以后如果申請后臺定位挟冠,info.plist需要同時配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription兩個字段镣屹;
-調(diào)用申請定位權(quán)限API圃郊,在用戶抉擇后,再次調(diào)用無效女蜈;
-如果調(diào)用requestWhenInUseAuthorization申請過使用期間的定位權(quán)限持舆,并且得到用戶許可,則之后仍可調(diào)用requestAlwaysAuthorization申請一次后臺定位權(quán)限(即權(quán)限升級)伪窖;
-iOS13后逸寓,直接調(diào)用requestAlwaysAuthorization申請權(quán)限時,權(quán)限彈窗與調(diào)用requestWhenInUseAuthorization一樣覆山,在app進(jìn)入后臺后竹伸,系統(tǒng)會擇機(jī)彈窗提示用戶是否要權(quán)限升級為始終允許;
-自2019年下半年起,蘋果商店上架app對后臺定位權(quán)限增加限制勋篓,如果info.plist中不包含NSLocationAlwaysUsageDescription/NSLocationAlwaysAndWhenInUseUsageDescription字段吧享,則在app代碼中不能出現(xiàn)符號requestAlwaysAuthorization,否則上架審核不通過譬嚣;
-****Info.plist 中的字段總結(jié)****
| iOS版本 | NSLocationWhenInUseUsageDescription | NSLocationAlwaysUsageDescription | NSLocationAlwaysAndWhenInUseUsageDescription | NSLocationTemporaryUsageDescriptionDictionary |
| :---: | :---: | :---: | :---: | :---: |
| iOS 8 | YES | YES | × | × |
| iOS 9 | YES | YES | × | × |
| iOS 10 | YES | YES | × | × |
| iOS 11 | YES | × | YES | × |
| iOS 12 | YES | × | YES | × |
| iOS 13 | YES | × | YES | × |
| iOS 14 | YES | × | YES | YES |
-****不同系統(tǒng)版本調(diào)用定位權(quán)限API差異****
****iOS8.0****
| - | Capabilities 關(guān) | Capabilities 開 |
| :--- | :---: | :---: |
| requestAlwaysAuthorization | 可以前臺定位钢颂、不可以后臺定位、無藍(lán)條 | 可以前臺定位拜银、可以后臺定位殊鞭、無藍(lán)條 |
| requestWhenInUseAuthorization | 可以前臺定位、不可以后臺定位尼桶、無藍(lán)條 | 可以前臺定位操灿、可以后臺定位、有藍(lán)條 |
| 無/用戶拒絕 | 無任何定位 | 無任何定位 |
****iOS9.0 - iOS12.0****
| | Capabilities 關(guān) | | Capabilities 開 | |
| --- | :---: | :---: | --- | --- |
| | allowsBackgroundLocationUpdates關(guān) | allowsBackgroundLocationUpdates開 | allowsBackgroundLocationUpdates關(guān) | allowsBackgroundLocationUpdates開 |
| requestAlwaysAuthorization | 可以前臺定位泵督、不可以后臺定位趾盐、無藍(lán)條 | iOS拋出Crash | 可以前臺定位、不可以后臺定位幌蚊、無藍(lán)條 | 可以前臺定位谤碳、可以后臺定位、無藍(lán)條 |
| requestWhenInUseAuthorization | 可以前臺定位溢豆、不可以后臺定位蜒简、無藍(lán)條 | iOS拋出Crash | 可以前臺定位、不可以后臺定位漩仙、無藍(lán)條 | 可以前臺定位搓茬、可以后臺定位、有藍(lán)條 |
| 無/用戶拒絕 | 無任何定位 | iOS拋出Crash | 無任何定位 | 無任何定位 |
三队他、獲取定位數(shù)據(jù)
1卷仑、單次定位
-iOS8.0版本不支持單次定位,需要調(diào)用連續(xù)定位startUpdatingLocation接口麸折,自行實現(xiàn)單次定位功能锡凝;
-iOS9.0及以后版本,可以調(diào)用單次定位API:
-(void)requestLocation API_AVAILABLE(ios(9.0));
2垢啼、連續(xù)定位
-開始連續(xù)定位:- (void)startUpdatingHeading;
-停止連續(xù)定位:- (void)stopUpdatingHeading窜锯;
3、定位CLLocationManager相關(guān)屬性
-定位活動類型@property(assign, nonatomic) CLActivityType activityType;
-typedef NS_ENUM(NSInteger, CLActivityType) {
CLActivityTypeOther = 1, //未知類型芭析,默認(rèn)值
CLActivityTypeAutomotiveNavigation, //駕車導(dǎo)航定位
CLActivityTypeFitness, //健身活動锚扎,如步行、跑步馁启、騎車等驾孔;
CLActivityTypeOtherNavigation, //其他交通工具導(dǎo)航,如火車、輪船等
CLActivityTypeAirborne //空中飛行定位(iOS12及以上版本)
};
-設(shè)置期望的定位精度@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
-當(dāng)精度設(shè)置較高時翠勉,定位服務(wù)會盡可能去獲取滿足desiredAccuracy的定位結(jié)果妖啥,但不一定會得到滿足期望的結(jié)果;
-kCLLocationAccuracyReduced為iOS14新特性眉菱,模糊定位迹栓,即使當(dāng)前精確定位開啟,如果設(shè)置該值俭缓,則會收到模糊定位結(jié)果;
-取值范圍:
kCLLocationAccuracyBestForNavigation; //導(dǎo)航高精度
kCLLocationAccuracyBest; //高精度
kCLLocationAccuracyNearestTenMeters; //10米
kCLLocationAccuracyHundredMeters; //100米
kCLLocationAccuracyKilometer; //1000米
kCLLocationAccuracyThreeKilometers; //3000米
kCLLocationAccuracyReduced; //模糊定位酥郭,誤差5000米(iOS14及以上版本)
-設(shè)置定位的最小更新距離@property(assign, nonatomic) CLLocationDistance distanceFilter;
-單位米华坦,默認(rèn)為 kCLDistanceFilterNone,表示只要檢測到設(shè)備位置發(fā)生變化就會更新位置信息不从;
-@property(nonatomic, assign) BOOL pausesLocationUpdatesAutomatically;
-是否允許系統(tǒng)自動暫停定位功能惜姐,設(shè)置為YES進(jìn)行后臺定位時,系統(tǒng)檢測到長時間沒有位置更新的時候椿息,將會暫停定位功能歹袁,當(dāng)app進(jìn)入前臺時會恢復(fù)定位功能;
3寝优、定位數(shù)據(jù)更新回調(diào)
--(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations;
-locations是按時間排序的CLLocation對象數(shù)組条舔,一般使用lastObject即為當(dāng)前最新定位信息;
四乏矾、定位權(quán)限API調(diào)用實踐
1孟抗、配置info.plist
-如果不需要使用后臺定位,則無需配置NSLocationAlwaysAndWhenInUseUsageDescription钻心、NSLocationAlwaysUsageDescription字段凄硼,并且代碼(包括使用的靜態(tài)庫)中不能出現(xiàn)requestAlwaysAuthorization符號;
[圖片上傳失敗...(image-3fd3da-1637218463749)]
2捷沸、開始定位
-此處直接在主線程開始定位摊沉,如果需要在子線程開始定位,則需要開啟子線程的runloop痒给,此處不再累述说墨。自蘋果X后,如果在子線程開始定位侈玄,會有UI不在主線程調(diào)用的警告婉刀,直接屏蔽或者忽略即可,不影響正常使用序仙;
//前置步驟:創(chuàng)建定位管理類CLLocationManager突颊,配置定位參數(shù)
//開始定位
- (void)startLocation{
//self.locationManager = [[CLLocationManager alloc]init];
//self.locationManager.allowsBackgroundLocationUpdates = YES;
//self.locationManager.delegate = self;
if([self locationServiceIsValid] == NO){
NSLog(@"用戶拒絕該app使用定位服務(wù)");
return;
}
//該場景下是否需要精確定位
BOOL isNeedFullAccuracy = YES;
//該場景下如果需要精確定位,則對應(yīng)的plist中配置的key
NSString *purposeKey = @"ExampleUsageDescription";
//判斷當(dāng)前定位權(quán)限是否ok
[self checkLocationAuthorizationStatus:self.locationManager
needFullAccuracy:isNeedFullAccuracy
purposeKey:purposeKey];
//開始連續(xù)定位
[self.locationManager startUpdatingLocation];
}
3、獲取當(dāng)前定位權(quán)限
//獲取當(dāng)前定位權(quán)限
- (CLAuthorizationStatus)authorizationStatus
{
if (@available(iOS 14.0, *)) {
return self.locationManager.authorizationStatus;
} else {
return [CLLocationManager authorizationStatus];
}
}
//當(dāng)前應(yīng)用是否可以使用/申請定位服務(wù)
- (BOOL)locationServiceIsValid{
if ([self authorizationStatus] == kCLAuthorizationStatusDenied ||
[self authorizationStatus] == kCLAuthorizationStatusRestricted) {
return NO;
}
return YES;
}
//當(dāng)前定位狀態(tài)是否可用
- (BOOL)locationAuthStatusIsValid{
if ([self locationServiceIsValid] == NO) {
return NO;
}
if ([self authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
return NO;
}
return YES;
}
4律秃、核實當(dāng)前權(quán)限狀態(tài)爬橡,判斷是否需要申請權(quán)限或者權(quán)限升級
-****如果app需要使用后臺定位****
//核實當(dāng)前權(quán)限狀態(tài),判斷是否需要申請權(quán)限或者權(quán)限升級
- (void)checkLocationAuthorizationStatus:(CLLocationManager *)manager
needFullAccuracy:(BOOL)isNeedFullAccuracy
purposeKey:(NSString *)purposeKey{
if([self authorizationStatus] == kCLAuthorizationStatusNotDetermined){
//如果沒有定位權(quán)限棒动,則需要先申請定位權(quán)限
//如果是iOS14申請權(quán)限彈窗時可以選擇精度開關(guān)吼虎,所以不用在單獨處理精度權(quán)限
[self requestLocationAuthorizationIfNeed:manager];
}else if(isNeedFullAccuracy){
//如果已經(jīng)有定位權(quán)限且需要精確定位
[self requestTemporaryFullAccuracyAuthorizationIfNeed:manager purposeKey:purposeKey];
}
}
//如果當(dāng)前場景需要精確定位,則可以申請一次臨時精確定位
- (void)requestTemporaryFullAccuracyAuthorizationIfNeed:(CLLocationManager *)manager
purposeKey:(NSString *)purposeKey
{
//如果是非iOS14系統(tǒng)填硕,則默認(rèn)為精確定位
if (@available(iOS 14.0, *)) {
//如果已經(jīng)獲得定位權(quán)限擂错,但精度權(quán)限只是模糊定位
if (manager.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) {
NSDictionary *locationTemporaryDictionary = [[NSBundle mainBundle]
objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"];
BOOL hasLocationTemporaryKey = locationTemporaryDictionary != nil && locationTemporaryDictionary.count != 0;
if (hasLocationTemporaryKey) {
//此API不能用于申請定位權(quán)限,只能用于從模糊定位升級為精確定位粱锐;申請定位權(quán)限只能調(diào)用
//requestWhen或requestAlways疙挺,如果沒有獲得定位權(quán)限,直接調(diào)用此API無效怜浅。
[manager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey completion:nil];
}else{
NSLog(@"如果需要使用臨時精確定位铐然,需要在Info.plist中添加 \
NSLocationTemporaryUsageDescriptionDictionary字段。");
}
}
}
}
//請求定位權(quán)限恶座,
- (void)requestLocationAuthorizationIfNeed:(CLLocationManager *)manager
{
//系統(tǒng)版本號
CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
//系統(tǒng)版本8+ && 沒有選擇過定位權(quán)限
if (systemVersion > 7.99 && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
//獲取info.plist中配置字段信息
BOOL hasAlwaysKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil;
BOOL hasWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil;
BOOL hasAlwaysAndWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"] != nil;
//如果是iOS11及以后版本搀暑。(當(dāng)前iOS11到13居多)
if (@available(iOS 11.0, *)){
if (hasAlwaysAndWhenInUseKey && hasWhenInUseKey)
{
//如果plist同時配置兩個字段,則兩個權(quán)限申請API都可以調(diào)用跨琳;
//建議直接調(diào)用requestAlwaysAuthorization即可
[manager requestAlwaysAuthorization];
}
else if (hasWhenInUseKey)
{
//如果plist只配置InUseKey自点,則只能調(diào)用使用時API
[manager requestWhenInUseAuthorization];
}
else{
NSLog(@"要在iOS11及以上版本使用定位服務(wù), 需要在Info.plist中添加 \
NSLocationAlwaysAndWhenInUseUsageDescription和NSLocationWhenInUseUsageDescription字段。");
}
}
else
{
if (hasAlwaysKey)
{
//如果plist配置hasAlwaysKey湾宙,則可以調(diào)用始終允許API
[manager requestAlwaysAuthorization];
}
else if (hasWhenInUseKey)
{
//如果plist配置hasAlwaysKey樟氢,則可以調(diào)用始終允許API
[manager requestWhenInUseAuthorization];
}
else
{
NSLog(@"要在iOS8到iOS10版本使用定位服務(wù), 需要在Info.plist中添加 \
NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription字段。");
}
}
}
}
-****如果app不需要使用后臺定位****
//核實當(dāng)前權(quán)限狀態(tài)侠鳄,判斷是否需要申請權(quán)限或者權(quán)限升級
- (void)checkLocationAuthorizationStatus:(CLLocationManager *)manager
needFullAccuracy:(BOOL)isNeedFullAccuracy
purposeKey:(NSString *)purposeKey{
if([self authorizationStatus] == kCLAuthorizationStatusNotDetermined){
//如果沒有定位權(quán)限埠啃,則需要先申請定位權(quán)限
//如果是iOS14申請權(quán)限彈窗時可以選擇精度開關(guān),所以不用在單獨處理精度權(quán)限
[self requestLocationAuthorizationIfNeed:manager];
}else if(isNeedFullAccuracy){
//如果已經(jīng)有定位權(quán)限且需要精確定位
[self requestTemporaryFullAccuracyAuthorizationIfNeed:manager purposeKey:purposeKey];
}
}
//如果當(dāng)前場景需要精確定位伟恶,則可以申請一次臨時精確定位
- (void)requestTemporaryFullAccuracyAuthorizationIfNeed:(CLLocationManager *)manager
purposeKey:(NSString *)purposeKey
{
//如果是非iOS14系統(tǒng)碴开,則默認(rèn)為精確定位
if (@available(iOS 14.0, *)) {
//如果已經(jīng)獲得定位權(quán)限,但精度權(quán)限只是模糊定位
if (manager.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) {
NSDictionary *locationTemporaryDictionary = [[NSBundle mainBundle]
objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"];
BOOL hasLocationTemporaryKey = locationTemporaryDictionary != nil && locationTemporaryDictionary.count != 0;
if (hasLocationTemporaryKey) {
//此API不能用于申請定位權(quán)限博秫,只能用于從模糊定位升級為精確定位潦牛;申請定位權(quán)限只能調(diào)用
//requestWhen或requestAlways,如果沒有獲得定位權(quán)限挡育,直接調(diào)用此API無效巴碗。
[manager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey completion:nil];
}else{
NSLog(@"如果需要使用臨時精確定位,需要在Info.plist中添加 \
NSLocationTemporaryUsageDescriptionDictionary字段即寒。");
}
}
}
}
//請求定位權(quán)限橡淆,
- (void)requestLocationAuthorizationIfNeed:(CLLocationManager *)manager
{
//系統(tǒng)版本號
CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
//系統(tǒng)版本8+ && 沒有選擇過定位權(quán)限
if (systemVersion > 7.99 && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
//獲取info.plist中配置字段信息
BOOL hasWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil;
if (hasWhenInUseKey)
{
//如果plist配置InUseKey召噩,則只能調(diào)用使用時API
[manager requestWhenInUseAuthorization];
}
else{
NSLog(@"要在iOS8及以上版本使用定位服務(wù), 需要在Info.plist中添加 \
NSLocationWhenInUseUsageDescription字段。");
}
}
}
5逸爵、定位權(quán)限狀態(tài)變更
//iOS13及以前版本回調(diào)
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
[self locationStatusDidChanged:[CLLocationManager authorizationStatus]];
}
//iOS14及以后版本回調(diào)
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager
{
if (@available(iOS 14.0, *)) {
[self locationStatusDidChanged:manager.authorizationStatus];
if([self locationAuthStatusIsValid]){
CLAccuracyAuthorization accuracyAuth = manager.accuracyAuthorization;
if (accuracyAuth == CLAccuracyAuthorizationReducedAccuracy){
NSLog(@"TODO: 可以模糊定位");
}else{
NSLog(@"TODO: 可以精確定位");
}
//該場景下是否需要精確定位
BOOL isNeedFullAccuracy = YES;
if (isNeedFullAccuracy == YES && accuracyAuth == CLAccuracyAuthorizationReducedAccuracy) {
NSLog(@"TODO: 該場景需要精確定位才可以使用具滴,請去設(shè)置中打開精確定位開關(guān)");
}
}
} else {
}
}
- (void)locationStatusDidChanged:(CLAuthorizationStatus)authStatus
{
switch (authStatus) {
case kCLAuthorizationStatusNotDetermined:
NSLog(@"可以申請定位權(quán)限");
break;
case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied:
NSLog(@"TODO: 沒有定位權(quán)限");
break;
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusAuthorizedWhenInUse:
NSLog(@"TODO: 擁有定位權(quán)限");
default:
break;
}
}
6、定位回調(diào)
//定位回調(diào)
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation *locationg = locations.lastObject;
NSLog(@"TODO: 收到定位數(shù)據(jù):%@",locationg);
}
五师倔、小結(jié)
定位信息作為用戶非常在意的隱私數(shù)據(jù)构韵,iOS開發(fā)者應(yīng)盡量遵循適用原則(即能滿足需求的最小權(quán)限)去獲取用戶定位信息。本文對iOS系統(tǒng)定位權(quán)限說明從8.0到14.0趋艘,其中關(guān)于API調(diào)用實踐是對應(yīng)的最大定位權(quán)限疲恢,開發(fā)者可以根據(jù)需求參考相對應(yīng)的部分。