美文网首页iOS开发
地图之CLLocationManager的使用

地图之CLLocationManager的使用

作者: 枫叶1234 | 来源:发表于2020-08-05 14:41 被阅读0次

授权状态

.Restricted 表示GPS功能受限于某些限制,无法使用定位服务,例如parental controls

kCLAuthorizationStatusNotDetermined //用户没有选择是否要使用定位服务(弹框没选择,或者根本没有弹框

kCLAuthorizationStatusRestricted //定位服务授权状态受限制,可能由于活动限制了定位服务,并且用户不能改变当前的权限,这个状态有可能不是用户拒绝的,但是也有可能是用户拒绝的。官网说的,具体没遇到过(遇到过的童鞋请告知谢谢)

kCLAuthorizationStatusDenied //用户在设置中关闭定位功能,或者用户明确的在弹框之后选择禁止定位

kCLAuthorizationStatusAuthorized //用户已经明确使用定位功能

kCLAuthorizationStatusAuthorizedWhenInUse //用户在使用期间允许使用定位功能

kCLAuthorizationStatusAuthorizedAlways //App始终允许使用定位功能

1.iOS8以前使用CLLocationManager

  • 1.导入头文件 <CoreLocation/CoreLocation.h>
  • 2.创建位置管理者 CLLocationManager , 并添加到属性。
  • 3.设置代理、遵守协议、实现代理方法,在代理方法中获取位置信息
  • 4.调用开始更新位置方法
  • 5.设置 每隔多远定位一次精确度,精确度越高越耗电,定位时间越长
// 1.设置位置管理者属性
@property (nonatomic, strong) CLLocationManager *lcManager;
// 2.判断是否打开了位置服务
if ([CLLocationManager locationServicesEnabled]) {
    // 创建位置管理者对象
    self.lcManager = [[CLLocationManager alloc] init];
    self.lcManager.delegate = self; // 设置代理
    // 设置定位距离过滤参数 (当本次定位和上次定位之间的距离大于或等于这个值时,调用代理方法)
    self.lcManager.distanceFilter = 100;
    self.lcManager.desiredAccuracy = kCLLocationAccuracyBest; // 设置定位精度(精度越高越耗电)
    [self.lcManager startUpdatingLocation]; // 开始更新位置
}
/** 获取到新的位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了");
}
/** 不能获取位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"获取定位失败");
}
  • 6.请求授权,iOS6之后,苹果开始加强保护用户隐私,在 Info.plist 文件中定义 Key提醒用户,提高用户允许定位的概率。
    image.png
  • 7.如果要后台定位,需要打开后台模式


    Snip20200731_1.png
Snip20200731_2.png Snip20200731_3.png

2.iOS8.0之后使用CLLocationManager

  • 1.iOS8之后,苹果又进一步加强了隐私保护,不会主动填出对话框,让用户选择
  • 2.需要实现两个方法(实现其一即可),并且 Info.plist 中设置对应的 key ,才会弹框

1.requestWhenInUseAuthorization

  • 1.当程序当前的授权状态为未决定时,在前台时请求定位服务许可时使用。需要先在 Info.plist 文件中设置一个Key:NSLocationWhenInUseUsageDescription, 如果不设置key,系统会忽略定位请求。
image.png
  • 2.当用户授权 when-in-use时,程序在前台时可以启动大部分定位服务。如果想要后台定位,需要开启后台定位模式,但在状态栏会出现蓝条提示用户程序正在进行定位。
[_lcManager requestWhenInUseAuthorization];
Snip20200731_4.png

iOS 后台定位 蓝条问题

image.png
蓝条问题的产生机理和处理办法:

CLLocationManager管理类的配置

_locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    _locationManager.distanceFilter = 100;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
 
    if ([[UIDevice currentDevice] systemVersion].floatValue >= 8) {
        /*
         有这么一种说法
         如果两个请求授权的方法都执行了,会出现以下情况
         1.requestWhenInUseAuthorization写在前面,第一次打开程序时请求授权,如果勾选了后台模式,进入后台会出现蓝条提示正在定位。当程序退出,第二次打开程序时requestAlwaysAuthorization 会再次请求授权。之后进入后台就不会出现蓝色状态栏。
         2.requestAlwaysAuthorization写在前面, requestWhenInUseAuthorization写在后面,只会在第一次打开程序时请求授权,因为requestAlwaysAuthorization得到的授权大于requestWhenInUseAuthorization得到的授权
         */
        [_locationManager requestAlwaysAuthorization];
        [_locationManager requestWhenInUseAuthorization];
    }
    if ([[UIDevice currentDevice] systemVersion].floatValue >= 9) {
        /*
         allowsBackgroundLocationUpdates:是否允许后台定位,默认为NO,只在iOS9.0之后起作用。
         设为YES时,必须保证Background Modes 中的Location updates处于选中状态,否则会抛出异常。
         在用户选择仅在使用应用期间获取位置权限的情况下,当应用进入后台,手机桌面顶部是否出现蓝条,这句代码起着关键性作用。
         首先,这句代码仅在requestWhenInUseAuthorization状态下才起作用,否则不起作用。当设为YES,就是允许在requestWhenInUseAuthorization此状态下,即使App进入后台,但是没杀死,那么就依然可以后台定位。并且顶部给个蓝条闪烁,目的是在于实时提醒用户:你这个App一直在获取你的位置信息哟,如果你感到不需要继续获取了,就杀死该App吧!所以一直蓝条闪烁。
         当设置为NO,就是在requestWhenInUseAuthorization状态下,App进入后台,立即停止后台定位。
         */
        _locationManager.allowsBackgroundLocationUpdates = YES;
        /*
         requestLocation和startUpdatingLocation这两个方法非常类似,都会立即返回结果,将获取的定位信息传递给委托对象的locationManager:didUpdateLocations:消息。
         不同点:
         startUpdatingLocation:可以持续获取定位。当设备移动的距离超过设定的distanceFilter属性值时,接收器会再次生成一条更新消息。
         requestLocation:只产生一次定位信息,在此之后定位服务就停止了。并且:当使用这个方法时,委托对象必须要实现locationManager:didUpdateLocations:和locationManager:didFailWithError:方法。
         */
        [_locationManager requestLocation];
    } else {
        [_locationManager startUpdatingLocation];
        
    }

其实在上段代码注释中已经写得较清楚了。

蓝条问题的产生前提:只在requestWhenInUseAuthorization这个状态下才会出现。

蓝条出现的目的:因为用户选择的是仅在应用使用期间获取位置,所以当app进入后台后,系统将以蓝条闪烁的形式不断提醒用户:主人,某某App一直在后台获取你的位置权限哟,如果你不需要用到了,你就直接将该App杀死吧,不然挺耗电的,如果有需要就当我没说哈。

蓝条出现与否的背后代码操控者:_locationManager.allowsBackgroundLocationUpdates = YES;如果不想出现蓝条,直接设置为NO,或者注释,因为默认为NO。

另外,蓝条出现与否的另一种说法:跟下面两句代码的执行顺序有关

        [_locationManager requestAlwaysAuthorization];
        [_locationManager requestWhenInUseAuthorization];

2.requestAlwaysAuthorization

  • 1.请求前后台定位服务授权,当授权状态为未决定时请求用户授权。前提是在 Info.plist 文件中包含key NSLocationAlwaysUsageDescription
image.png Snip20200731_5.png

这边为什么还是显示的User的文档呢?

因为:在ios11中,NSLocationAlwaysUsageDeion 被当做NSLocationWhenInUseUsageDeion 来处理了

在IOS11,原有的NSLocationAlwaysUsageDeion被降级为NSLocationWhenInUseUsageDeion。因此,在原来项目中使用requestAlwaysAuthorization获取定位权限,而未在plist文件中配置NSLocationAlwaysAndWhenInUseUsageDeion,系统框不会弹出。建议新旧key值都在plist里配置,反正我试下来是没有问题,唯一的区别是使用requestAlwaysAuthorization获取权限 IOS11系统弹框会把几种权限级别全部列出,供用户选择,显然更人性化了哈~~

在plist文件中如果不包含“ NSLocationAlwaysAndWhenInUseUsageDeion”

会报:The app's Info.plist must contain both “NSLocationAlwaysAndWhenInUseUsageDescription” and “NSLocationWhenInUseUsageDescription” keys with string values explaining to the user how the app uses this data 这个错误

还有一种情况:

截屏2020-07-31 下午5.28.59.png

当你第一次用requestWhenInUseAuthorization请求了
会弹出

Snip20200731_4.png

如果第二次用“requestAlwaysAuthorization”请求,就会弹出


image.png

这边的文案显示的plist中配置的 NSLocationAlwaysAndWhenInUseUsageDeion的文案
说明弹出这个,必须在plist中配置NSLocationAlwaysAndWhenInUseUsageDeion

3.注意

  • 1.iOS8之后,如果想要定位,必须调用 requestWhenInUseAuthorizationrequestAlwaysAuthorization方法。

  • 2.如果两个请求授权的方法都执行了,会出现以下情况

    • 1.when-in-use写在前面,第一次打开程序时请求授权,如果勾选了后台模式,进入后台会出现蓝条提示正在定位。当程序退出,第二次打开程序时 Always 会再次请求授权。之后进入后台就不会出现蓝条了(前后台都能定位)

    • 2.Always写在前面, when-in-use写在后面,只会在第一次打开程序时请求授权,因为 Always得到的授权大于when-in-use的到的授权

4.判断是否开启了定位服务

  • 在启动更新位置之前要先判断是否开启了定位服务
if ([CLLocationManager locationServicesEnabled]) { // 判断是否打开了位置服务
        [self.lcManager startUpdatingLocation]; // 开始更新位置
    }

5.适配版本号的方法

  • when-in-useAlways 都是iOS8之后出现的方法,如果不进行版本适配,运行在iOS7上就会crash,此时需要做版本号判断

  • 1.判断版本号

if ([[UIDevice currentDevice].systemVersion floatValue] >=8.0 ) {
[_lcManager requestAlwaysAuthorization];
}
  • 2.适配版本的另一种方法
if ([_lcManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
            [_lcManager requestWhenInUseAuthorization];
        }

6.监听定位服务状态的改变

  • 实现代理方法,判断定位服务的状态
/** 定位服务状态改变时调用*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户还未决定授权");
            break;
        }
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            break;
        }
        case kCLAuthorizationStatusDenied:
        {
            // 类方法,判断是否开启定位服务
            if ([CLLocationManager locationServicesEnabled]) {
                NSLog(@"定位服务开启,被拒绝");
            } else {
                NSLog(@"定位服务关闭,不可用");
            }
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:
        {
            NSLog(@"获得前后台授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"获得前台授权");
            break;
        }
        default:
            break;
    }
}

7.代理方法返回的 locations 信息

  • 当位置管理器,获取到位置后,调用 locationManager:didUpdateLocations:方法,返回的类型为 CLLocation 的位置信息数组,以下为数组包含的属性

  • 1.coordinate : 当前位置的坐标
    *latitude : 纬度
    *longitude : 经度

  • 2.altitude : 海拔,高度

  • 3.horizontalAccuracy : 纬度和经度的精度

  • 4.verticalAccuracy : 垂直精度(获取不到海拔时为负数)

  • 5.course : 行进方向(真北)

  • 6.speed : 以米/秒为单位的速度

  • 7.description : 位置描述信息

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations firstObject];
    NSLog(@"%@", location);
}

3.iOS9.0之后使用CLLocationManager

  • 1.iOS9.0之后有一种新的请求定位的方法 requestLocation

  • 2.作用:按照定位精确度从低到高进行排序,逐个进行定位。如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界。

  • 3.注意:

  • 1.必须实现 ocationManager:didUpdateLocations:locationManager:didFailWithError 方法,但是只调用一次

  • 2.不能与startUpdatingLocation同时使用

    if ([CLLocationManager locationServicesEnabled]) { // 判断是否打开了位置服务
        [self.lcManager requestLocation];
    }
  • 4.实现 requestWhenInUseAuthorizationrequestAlwaysAuthorization 方法,并设置对应的 key
if ([[UIDevice currentDevice].systemVersion floatValue] >=8.0 ) {
     // iOS0.0:如果当前的授权状态是使用是授权,那么App退到后台后,将不能获取用户位置,即使勾选后台模式:location
    [_lcManager requestWhenInUseAuthorization];
    }
  • 5.必须勾选后台模式,并设置 allowsBackgroundLocationUpdates 属性为YES(默认是NO)

  • 1.当定位完成时,设置为NO,并且不再定位跟踪

  • 2.使用 -responsdToSelector: 判断

// iOS9.0+ 要想继续获取位置,需要使用以下属性进行设置(注意勾选后台模式:location)但会出现蓝条
if ([_lcManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
    _lcManager.allowsBackgroundLocationUpdates = YES;
}

相关文章

网友评论

    本文标题:地图之CLLocationManager的使用

    本文链接:https://www.haomeiwen.com/subject/utvsrktx.html