前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS-定位

iOS-定位

作者头像
GuangdongQi
发布2021-11-24 17:04:25
1.2K0
发布2021-11-24 17:04:25
举报
文章被收录于专栏:Guangdong QiGuangdong Qi

一、前言

代码语言:javascript
复制
大数据时代,用户对自己的隐私安全越来越关注,所以,随着iOS系统更新,苹果对用户隐私相关(定位、相册、网络、粘贴板等)权限控制持续升级。其中定位权限相关申请API与配置项较多,本文旨在记录说明 iOS8.0 - 14.0beta 从权限申请到获取定位数据流程。

内容包括定位权限、获取定位数据、定位权限API调用实践。定位权限模块按照系统相关性分别介绍该系统下权限配置与API调用细节、注意事项与表格总结;获取定位数据模块介绍定位关键参数、单次/连续定位等;调用实践模块介绍了从 iOS8.0 - 14.0beta 系统定位权限的适配实践。

二、定位权限

1、iOS8.*

-前台定位

-需要在info.plist配置NSLocationWhenInUseUsageDescription字段;

-首次使用定位时,通过API接口requestWhenInUseAuthorization申请应用使用时权限;

注意:此权限下,如果Xcode勾选 Capabilities -> UIBackgroundModes > Location updates,则app退到后台仍可获取定位数据,但此时在手机上方会有定位小蓝条提示;

-后台定位

-需要在info.plist配置NSLocationAlwaysUsageDescription字段;

-需要Xcode勾选 Capabilities -> UIBackgroundModes > Location updates;

-首次使用定位时,通过API接口requestAlwaysAuthorization申请应用未使用时权限;

2、iOS9.与iOS10.

-****前台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription字段;

-首次使用定位时,通过API接口requestWhenInUseAuthorization申请应用使用时权限,如下图;

代码语言:javascript
复制
 注意:此权限下,如果Xcode勾选 Capabilities -> UIBackgroundModes > Location updates并且allowsBackgroundLocationUpdates设为YES,则app退到后台仍可获取定位数据,但此时在手机上方会有定位小蓝条提示;

-****后台定位****

-需要在info.plist配置NSLocationAlwaysUsageDescription字段;

-需要Xcode勾选 Capabilities -> UIBackgroundModes > Location updates;

-需要CLLocationManager设置allowsBackgroundLocationUpdates为YES;

-首次使用定位时,通过API接口requestAlwaysAuthorization申请应用未使用时权限,如下图;

-与iOS8.版本相比不同点***

-iOS9.后台增加了allowsBackgroundLocationUpdates属性,可以认为在iOS8.下allowsBackgroundLocationUpdates永远为YES;

3、iOS11.与iOS12.

-****前台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription字段;

-首次使用定位时,通过API接口requestWhenInUseAuthorization申请应用使用时权限,如下图;

注意:此权限下,如果Xcode勾选 Capabilities -> UIBackgroundModes > Location updates并且allowsBackgroundLocationUpdates设为YES,则app退到后台仍可获取定位数据,但此时在手机上方会有定位小蓝条提示,此小蓝条不可隐藏;

-****后台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription字段;

-需要Xcode勾选 Capabilities -> UIBackgroundModes > Location updates;

-需要CLLocationManager设置allowsBackgroundLocationUpdates为YES;

-首次使用定位时,通过API接口requestAlwaysAuthorization申请应用未使用时权限,如下图;

代码语言:javascript
复制
 注意:此权限下,当app在后台时,系统默认不展示定位小蓝条,可通过showsBackgroundLocationIndicator控制小蓝条是否显示;

-与iOS10.版本相比不同点***

-iOS11.*变更了后台定位权限配置字段;

-iOS11.*以后如果申请后台定位,info.plist需要同时配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription两个字段;

-iOS11.增加了showsBackgroundLocationIndicator属性,当拥有后台定位权限时,用于控制定位小蓝条是否显示。可以认为在iOS10.之前showsBackgroundLocationIndicator永远为NO;

4、iOS13.*

-****前台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription字段;

-首次使用定位时,通过API接口requestWhenInUseAuthorization申请应用使用时权限;

注意:权限申请弹窗与之前版本不一致,新增了允许一次选项;如果用户选择允许一次后,下次在使用app时,仍可重新调用API申请定位权限;如下图

-****后台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription字段;

-需要Xcode勾选 Capabilities -> UIBackgroundModes > Location updates;

-需要CLLocationManager设置allowsBackgroundLocationUpdates为YES;

-首次使用定位时,通过API接口requestAlwaysAuthorization申请权限;

代码语言:javascript
复制
 注意:1)直接调用requestAlwaysAuthorization申请权限时,权限弹窗与调用requestWhenInUseAuthorization一样,如上图,用户只可以选择应用使用时或者只允许一次。不同点:当选择使用app时允许选项后,状态变更的回调为kCLAuthorizationStatusAuthorizedAlways;并且当app退到后台后,系统会择机弹窗提示用户是否要升级权限为始终允许。如下图:
代码语言:javascript
复制
2)如果想要在应用使用期间弹窗申请始终允许,则需要先调用requestWhenInUseAuthorization,并且获得应用使用期间定位权限,之后在调用requestAlwaysAuthorization则可弹窗申请始终允许,如下图;(感觉不是太友好,不建议使用)

-与iOS12.版本相比不同点***

-使用应用期间的定位权限增加了允许一次选项;

-不能直接申请后台定位权限,需要用户先选择应用使用期间的定位权限后,在进行权限升级;

5、iOS14.*(beta版本)

-****前台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription字段;

-首次使用定位时,通过API接口requestWhenInUseAuthorization申请应用使用时权限;

注意:权限申请弹窗与之前版本不一致,新增了精确位置开关,新增了小地图展示当前位置;小地图的显示,支持在手机定位设置中选择,如果选择关闭不显示则手机中所有app都不显示此小地图。如下图

-****后台定位****

-需要在info.plist配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription字段;

-需要Xcode勾选 Capabilities -> UIBackgroundModes > Location updates;

-需要CLLocationManager设置allowsBackgroundLocationUpdates为YES;

-首次使用定位时,通过API接口requestAlwaysAuthorization申请权限;

-****新增精度权限****

-需要在info.plist配置NSLocationTemporaryUsageDescriptionDictionary,如下:

代码语言:javascript
复制
<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));可以获取当前的定位精度权限。

-在app已经获得定位权限之后,并且当前用户选择的是模糊定位,则允许应用申请一次临时精确定位权限,申请api为- (void)requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(NSString )purposeKey completion:(void(^)(NSError ))completion; 其中purposeKey既为plist中配置字典中的key,可以有多个,对应app中不同的定位需求场景;注意:**此API不能用于申请定位权限,只能用于从模糊定位升级为精确定位;申请定位权限只能调用requestWhen或requestAlways,如果没有获得定位权限,直接调用此API无效。如下图

-如果app默认不使用精确定位,则可以在info.plist中配置NSLocationDefaultAccuracyReduced字段,配置该字段后,申请定位权限的小地图中不在有精确定位的开关,即为关。如下面图示

代码语言:javascript
复制
  -需要注意该字段类型为Boolean,如果为其他类型则不起效;

  -配置该字段后,申请定位权限的小地图左上角则没有精确开关,默认关闭,如下面图示。但是如果info.plist中配置了NSLocationTemporaryUsageDescriptionDictionary,则仍可以申请临时的精确定位权限;

  -⚠️:测试期间使用Xcode12 beta1到beta4,直接使用info.plist的Property List添加NSLocationDefaultAccuracyReduced字段只能是string,所以会造成不起效的问题,如果您也遇到类似问题,可以点击info.plist右键Open As -> Source Code,即使用源码直接添加既可起效;
代码语言:javascript
复制
<key>NSLocationDefaultAccuracyReduced</key>

<true/>

[图片上传失败...(image-24baae-1637218463749)]

-与iOS13.版本相比不同点***

-权限申请弹窗与之前版本不一致;

-新增精度权限相关plist设置、授权、读取;

-新增临时一次从模糊定位升级精确定位API;

-新增定位权限变更回调;

6、定位权限更新回调

-****iOS13.*及以前:****- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;

-如主动获取定位权限可使用类方法:+ (CLAuthorizationStatus)authorizationStatus;

-CLAuthorizationStatus枚举取值

typedef NS_ENUM(int, CLAuthorizationStatus) {

kCLAuthorizationStatusNotDetermined = 0, //用户没有决定是否使用定位服务

kCLAuthorizationStatusRestricted, //定位服务授权状态受限制

kCLAuthorizationStatusDenied, //用户拒绝/定位总开关关闭

kCLAuthorizationStatusAuthorizedAlways, //始终允许

kCLAuthorizationStatusAuthorizedWhenInUse, //在应用使用期间

kCLAuthorizationStatusAuthorized //已经废弃,等同于始终允许

};

-iOS14.及以后***:- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager;

-通过manager.authorizationStatus对象方法获取当前定位权限,此方法在iOS13及以前版本是类方法;

-通过manager.accuracyAuthorization对象方法获取当前精度权限;

-CLAccuracyAuthorization枚举取值

typedef NS_ENUM(NSInteger, CLAccuracyAuthorization) {

CLAccuracyAuthorizationFullAccuracy, //精确定位

CLAccuracyAuthorizationReducedAccuracy, //模糊定位

};

7、总结

-****定位权限注意事项****

-iOS11以后如果申请后台定位,info.plist需要同时配置NSLocationWhenInUseUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription两个字段;

-调用申请定位权限API,在用户抉择后,再次调用无效;

-如果调用requestWhenInUseAuthorization申请过使用期间的定位权限,并且得到用户许可,则之后仍可调用requestAlwaysAuthorization申请一次后台定位权限(即权限升级);

-iOS13后,直接调用requestAlwaysAuthorization申请权限时,权限弹窗与调用requestWhenInUseAuthorization一样,在app进入后台后,系统会择机弹窗提示用户是否要权限升级为始终允许;

-自2019年下半年起,苹果商店上架app对后台定位权限增加限制,如果info.plist中不包含NSLocationAlwaysUsageDescription/NSLocationAlwaysAndWhenInUseUsageDescription字段,则在app代码中不能出现符号requestAlwaysAuthorization,否则上架审核不通过;

-****Info.plist 中的字段总结****

| 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 |

-****不同系统版本调用定位权限API差异****

****iOS8.0****

| - | Capabilities 关 | Capabilities 开 |

| :--- | :---: | :---: |

| requestAlwaysAuthorization | 可以前台定位、不可以后台定位、无蓝条 | 可以前台定位、可以后台定位、无蓝条 |

| requestWhenInUseAuthorization | 可以前台定位、不可以后台定位、无蓝条 | 可以前台定位、可以后台定位、有蓝条 |

| 无/用户拒绝 | 无任何定位 | 无任何定位 |

****iOS9.0 - iOS12.0****

| | Capabilities 关 | | Capabilities 开 | |

| --- | :---: | :---: | --- | --- |

| | allowsBackgroundLocationUpdates关 | allowsBackgroundLocationUpdates开 | allowsBackgroundLocationUpdates关 | allowsBackgroundLocationUpdates开 |

| requestAlwaysAuthorization | 可以前台定位、不可以后台定位、无蓝条 | iOS抛出Crash | 可以前台定位、不可以后台定位、无蓝条 | 可以前台定位、可以后台定位、无蓝条 |

| requestWhenInUseAuthorization | 可以前台定位、不可以后台定位、无蓝条 | iOS抛出Crash | 可以前台定位、不可以后台定位、无蓝条 | 可以前台定位、可以后台定位、有蓝条 |

| 无/用户拒绝 | 无任何定位 | iOS抛出Crash | 无任何定位 | 无任何定位 |

三、获取定位数据

1、单次定位

-iOS8.0版本不支持单次定位,需要调用连续定位startUpdatingLocation接口,自行实现单次定位功能;

-iOS9.0及以后版本,可以调用单次定位API:

-(void)requestLocation API_AVAILABLE(ios(9.0));

2、连续定位

-开始连续定位:- (void)startUpdatingHeading;

-停止连续定位:- (void)stopUpdatingHeading;

3、定位CLLocationManager相关属性

-定位活动类型@property(assign, nonatomic) CLActivityType activityType;

-typedef NS_ENUM(NSInteger, CLActivityType) {

CLActivityTypeOther = 1, //未知类型,默认值

CLActivityTypeAutomotiveNavigation, //驾车导航定位

代码语言:javascript
复制
CLActivityTypeFitness,                        //健身活动,如步行、跑步、骑车等;

CLActivityTypeOtherNavigation, //其他交通工具导航,如火车、轮船等

代码语言:javascript
复制
CLActivityTypeAirborne                       //空中飞行定位(iOS12及以上版本)

};

-设置期望的定位精度@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;

-当精度设置较高时,定位服务会尽可能去获取满足desiredAccuracy的定位结果,但不一定会得到满足期望的结果;

-kCLLocationAccuracyReduced为iOS14新特性,模糊定位,即使当前精确定位开启,如果设置该值,则会收到模糊定位结果;

-取值范围:

kCLLocationAccuracyBestForNavigation; //导航高精度

kCLLocationAccuracyBest; //高精度

kCLLocationAccuracyNearestTenMeters; //10米

kCLLocationAccuracyHundredMeters; //100米

kCLLocationAccuracyKilometer; //1000米

kCLLocationAccuracyThreeKilometers; //3000米

kCLLocationAccuracyReduced; //模糊定位,误差5000米(iOS14及以上版本)

-设置定位的最小更新距离@property(assign, nonatomic) CLLocationDistance distanceFilter;

-单位米,默认为 kCLDistanceFilterNone,表示只要检测到设备位置发生变化就会更新位置信息;

-@property(nonatomic, assign) BOOL pausesLocationUpdatesAutomatically;

-是否允许系统自动暂停定位功能,设置为YES进行后台定位时,系统检测到长时间没有位置更新的时候,将会暂停定位功能,当app进入前台时会恢复定位功能;

3、定位数据更新回调

--(void)locationManager:(CLLocationManager *)manager

didUpdateLocations:(NSArray *)locations;

-locations是按时间排序的CLLocation对象数组,一般使用lastObject即为当前最新定位信息;

四、定位权限API调用实践

1、配置info.plist

-如果不需要使用后台定位,则无需配置NSLocationAlwaysAndWhenInUseUsageDescription、NSLocationAlwaysUsageDescription字段,并且代码(包括使用的静态库)中不能出现requestAlwaysAuthorization符号;

[图片上传失败...(image-3fd3da-1637218463749)]

2、开始定位

-此处直接在主线程开始定位,如果需要在子线程开始定位,则需要开启子线程的runloop,此处不再累述。自苹果X后,如果在子线程开始定位,会有UI不在主线程调用的警告,直接屏蔽或者忽略即可,不影响正常使用;

代码语言:javascript
复制
//前置步骤:创建定位管理类CLLocationManager,配置定位参数

//开始定位

- (void)startLocation{

//self.locationManager = [[CLLocationManager alloc]init];

//self.locationManager.allowsBackgroundLocationUpdates = YES;

//self.locationManager.delegate = self;

    if([self locationServiceIsValid] == NO){

        NSLog(@"用户拒绝该app使用定位服务");

        return;

    }

    //该场景下是否需要精确定位

    BOOL isNeedFullAccuracy = YES;

    //该场景下如果需要精确定位,则对应的plist中配置的key

    NSString *purposeKey = @"ExampleUsageDescription";

    //判断当前定位权限是否ok

    [self checkLocationAuthorizationStatus:self.locationManager

                           needFullAccuracy:isNeedFullAccuracy

                                 purposeKey:purposeKey];

    //开始连续定位

    [self.locationManager startUpdatingLocation];

}
3、获取当前定位权限
代码语言:javascript
复制
//获取当前定位权限

- (CLAuthorizationStatus)authorizationStatus

{

    if (@available(iOS 14.0, *)) {

        return self.locationManager.authorizationStatus;

    } else {

        return [CLLocationManager authorizationStatus];

    }

}

//当前应用是否可以使用/申请定位服务

- (BOOL)locationServiceIsValid{

    if ([self authorizationStatus] == kCLAuthorizationStatusDenied ||

        [self authorizationStatus] == kCLAuthorizationStatusRestricted) {

        return NO;

    }

    return YES;

}

//当前定位状态是否可用

- (BOOL)locationAuthStatusIsValid{

    if ([self locationServiceIsValid] == NO) {

        return  NO;

    }

    if ([self authorizationStatus] == kCLAuthorizationStatusNotDetermined) {

        return NO;

    }

    return YES;

}
4、核实当前权限状态,判断是否需要申请权限或者权限升级

-****如果app需要使用后台定位****

代码语言:javascript
复制
//核实当前权限状态,判断是否需要申请权限或者权限升级

- (void)checkLocationAuthorizationStatus:(CLLocationManager *)manager

                         needFullAccuracy:(BOOL)isNeedFullAccuracy

                                purposeKey:(NSString *)purposeKey{

      if([self authorizationStatus] == kCLAuthorizationStatusNotDetermined){

          //如果没有定位权限,则需要先申请定位权限

          //如果是iOS14申请权限弹窗时可以选择精度开关,所以不用在单独处理精度权限

          [self requestLocationAuthorizationIfNeed:manager];

      }else if(isNeedFullAccuracy){

          //如果已经有定位权限且需要精确定位

            [self requestTemporaryFullAccuracyAuthorizationIfNeed:manager purposeKey:purposeKey];

      }

}

//如果当前场景需要精确定位,则可以申请一次临时精确定位

- (void)requestTemporaryFullAccuracyAuthorizationIfNeed:(CLLocationManager *)manager

                                             purposeKey:(NSString *)purposeKey

{

    //如果是非iOS14系统,则默认为精确定位

    if (@available(iOS 14.0, *)) {

        //如果已经获得定位权限,但精度权限只是模糊定位

        if (manager.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) {

            NSDictionary *locationTemporaryDictionary = [[NSBundle mainBundle]

                        objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"];

            BOOL hasLocationTemporaryKey = locationTemporaryDictionary != nil && locationTemporaryDictionary.count != 0;

            if (hasLocationTemporaryKey) {

                //此API不能用于申请定位权限,只能用于从模糊定位升级为精确定位;申请定位权限只能调用

                //requestWhen或requestAlways,如果没有获得定位权限,直接调用此API无效。

                [manager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey completion:nil];

            }else{

                NSLog(@"如果需要使用临时精确定位,需要在Info.plist中添加 \

                NSLocationTemporaryUsageDescriptionDictionary字段。");

            }

        }

    }

 }

//请求定位权限,

- (void)requestLocationAuthorizationIfNeed:(CLLocationManager *)manager

{

    //系统版本号

    CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

    //系统版本8+ && 没有选择过定位权限

    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及以后版本。(当前iOS11到13居多)

        if (@available(iOS 11.0, *)){

            if (hasAlwaysAndWhenInUseKey && hasWhenInUseKey)

            {

                //如果plist同时配置两个字段,则两个权限申请API都可以调用;

                //建议直接调用requestAlwaysAuthorization即可

                [manager requestAlwaysAuthorization];

            }

            else if (hasWhenInUseKey)

            {

                //如果plist只配置InUseKey,则只能调用使用时API

                [manager requestWhenInUseAuthorization];

            }

            else{

                NSLog(@"要在iOS11及以上版本使用定位服务, 需要在Info.plist中添加 \

                NSLocationAlwaysAndWhenInUseUsageDescription和NSLocationWhenInUseUsageDescription字段。");

            }

        }

        else

        {

            if (hasAlwaysKey)

            {

                //如果plist配置hasAlwaysKey,则可以调用始终允许API

                [manager requestAlwaysAuthorization];

            }

            else if (hasWhenInUseKey)

            {

                //如果plist配置hasAlwaysKey,则可以调用始终允许API

                [manager requestWhenInUseAuthorization];

            }

            else

            {

                NSLog(@"要在iOS8到iOS10版本使用定位服务, 需要在Info.plist中添加 \

                NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription字段。");

            }

        }

    }

}

-****如果app不需要使用后台定位****

代码语言:javascript
复制
//核实当前权限状态,判断是否需要申请权限或者权限升级

- (void)checkLocationAuthorizationStatus:(CLLocationManager *)manager

                         needFullAccuracy:(BOOL)isNeedFullAccuracy

                                purposeKey:(NSString *)purposeKey{

      if([self authorizationStatus] == kCLAuthorizationStatusNotDetermined){

          //如果没有定位权限,则需要先申请定位权限

          //如果是iOS14申请权限弹窗时可以选择精度开关,所以不用在单独处理精度权限

          [self requestLocationAuthorizationIfNeed:manager];

      }else if(isNeedFullAccuracy){

          //如果已经有定位权限且需要精确定位

            [self requestTemporaryFullAccuracyAuthorizationIfNeed:manager purposeKey:purposeKey];

      }

}

//如果当前场景需要精确定位,则可以申请一次临时精确定位

- (void)requestTemporaryFullAccuracyAuthorizationIfNeed:(CLLocationManager *)manager

                                             purposeKey:(NSString *)purposeKey

{

    //如果是非iOS14系统,则默认为精确定位

    if (@available(iOS 14.0, *)) {

        //如果已经获得定位权限,但精度权限只是模糊定位

        if (manager.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) {

            NSDictionary *locationTemporaryDictionary = [[NSBundle mainBundle]

                        objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"];

            BOOL hasLocationTemporaryKey = locationTemporaryDictionary != nil && locationTemporaryDictionary.count != 0;

            if (hasLocationTemporaryKey) {

                //此API不能用于申请定位权限,只能用于从模糊定位升级为精确定位;申请定位权限只能调用

                //requestWhen或requestAlways,如果没有获得定位权限,直接调用此API无效。

                [manager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey completion:nil];

            }else{

                NSLog(@"如果需要使用临时精确定位,需要在Info.plist中添加 \

                NSLocationTemporaryUsageDescriptionDictionary字段。");

            }

        }

    }

 }

//请求定位权限,

- (void)requestLocationAuthorizationIfNeed:(CLLocationManager *)manager

{

    //系统版本号

    CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

    //系统版本8+ && 没有选择过定位权限

    if (systemVersion > 7.99 && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)

    {

        //获取info.plist中配置字段信息

        BOOL hasWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil;

        if (hasWhenInUseKey)

        {

            //如果plist配置InUseKey,则只能调用使用时API

            [manager requestWhenInUseAuthorization];

        }

        else{

            NSLog(@"要在iOS8及以上版本使用定位服务, 需要在Info.plist中添加 \

            NSLocationWhenInUseUsageDescription字段。");

        }

    }

}
5、定位权限状态变更
代码语言:javascript
复制
//iOS13及以前版本回调

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status

{

    [self locationStatusDidChanged:[CLLocationManager authorizationStatus]];

}

//iOS14及以后版本回调

- (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: 该场景需要精确定位才可以使用,请去设置中打开精确定位开关");

            }

        }

    } else {

    }

}

- (void)locationStatusDidChanged:(CLAuthorizationStatus)authStatus

{

    switch (authStatus) {

        case kCLAuthorizationStatusNotDetermined:

            NSLog(@"可以申请定位权限");

            break;

        case kCLAuthorizationStatusRestricted:

        case kCLAuthorizationStatusDenied:

            NSLog(@"TODO: 没有定位权限");

            break;

        case kCLAuthorizationStatusAuthorizedAlways:

        case kCLAuthorizationStatusAuthorizedWhenInUse:

            NSLog(@"TODO: 拥有定位权限");

        default:

            break;

    }

}
6、定位回调
代码语言:javascript
复制
//定位回调

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations

{

    CLLocation *locationg = locations.lastObject;

    NSLog(@"TODO: 收到定位数据:%@",locationg);

}

五、小结

定位信息作为用户非常在意的隐私数据,iOS开发者应尽量遵循适用原则(即能满足需求的最小权限)去获取用户定位信息。本文对iOS系统定位权限说明从8.0到14.0,其中关于API调用实践是对应的最大定位权限,开发者可以根据需求参考相对应的部分。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021/11/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、定位权限
    • 1、iOS8.*
      • 2、iOS9.与iOS10.
        • 3、iOS11.与iOS12.
          • 4、iOS13.*
            • 5、iOS14.*(beta版本)
              • 6、定位权限更新回调
                • 7、总结
                • 三、获取定位数据
                  • 1、单次定位
                    • 2、连续定位
                      • 3、定位CLLocationManager相关属性
                        • 3、定位数据更新回调
                        • 四、定位权限API调用实践
                          • 1、配置info.plist
                            • 2、开始定位
                              • 3、获取当前定位权限
                                • 4、核实当前权限状态,判断是否需要申请权限或者权限升级
                                  • 5、定位权限状态变更
                                    • 6、定位回调
                                    • 五、小结
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档