iOS-定位

2021-11-24 17:04:25 浏览数 (1)

一、前言

代码语言: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调用实践是对应的最大定位权限,开发者可以根据需求参考相对应的部分。

0 人点赞