美文网首页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