美文网首页iOS
iOS CoreLocation的使用及后台持续定位

iOS CoreLocation的使用及后台持续定位

作者: Double_Chen | 来源:发表于2018-01-31 10:46 被阅读1243次

    import <CoreLocation/CoreLocation.h>

    本文描述了如何用CoreLocation框架实现以下功能:

    • 申请定位权限
    • 查看定位权限
    • 获取定位信息
    • 获取指南针信息
    • 地理编码
    • 反地理编码
    • 后台定位低功耗设置

    要使用定位功能,首先需要在info.plist文件中添加两个字段,声明是需要持续定位还是应用使用期间定位。

     Privacy - Location When In Use Usage Description
     Privacy - Location Always Usage Description
    

    初始化LocationManger对象

    //别忘了遵循代理CLLocationManagerDelegate
    - (void)initializedLocationManager {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;  
        /*
         定位精确度
         kCLLocationAccuracyBestForNavigation    最适合导航
         kCLLocationAccuracyBest    精度最好的
         kCLLocationAccuracyNearestTenMeters    附近10米
         kCLLocationAccuracyHundredMeters    附近100米
         kCLLocationAccuracyKilometer    附近1000米
         kCLLocationAccuracyThreeKilometers    附近3000米
         */
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        /*
         每隔多少米更新一次位置,即定位更新频率
         */
        _locationManager.distanceFilter = kCLDistanceFilterNone; //系统默认值
    }
    

    申请定位权限

    - (void)requestPermission {
        
        //iOS9.0以上系统除了配置info之外,还需要添加这行代码,才能实现后台定位,否则程序会crash
        if (@available(iOS 9.0, *)) {
            _locationManager.allowsBackgroundLocationUpdates = YES;
        } else {
            // Fallback on earlier versions
        }
        [_locationManager requestAlwaysAuthorization];  //一直保持定位
        [_locationManager requestWhenInUseAuthorization]; //使用期间定位
    }
    

    查看定位权限

    - (BOOL)checkPermission {
        /*
         kCLAuthorizationStatusNotDetermined                  //用户尚未对该应用程序作出选择
         kCLAuthorizationStatusRestricted                     //应用程序的定位权限被限制
         kCLAuthorizationStatusAuthorizedAlways               //允许一直获取定位
         kCLAuthorizationStatusAuthorizedWhenInUse            //在使用时允许获取定位
         kCLAuthorizationStatusAuthorized                     //已废弃,相当于一直允许获取定位
         kCLAuthorizationStatusDenied                         //拒绝获取定位
         */
        if ([CLLocationManager locationServicesEnabled]) {
            switch ([CLLocationManager authorizationStatus]) {
                case kCLAuthorizationStatusNotDetermined:
                    NSLog(@"用户尚未进行选择");
                    break;
                case kCLAuthorizationStatusRestricted:
                    NSLog(@"定位权限被限制");
                    break;
                case kCLAuthorizationStatusAuthorizedAlways:
                case kCLAuthorizationStatusAuthorizedWhenInUse:
                    NSLog(@"用户允许定位");
                    return YES;
                    break;
                case kCLAuthorizationStatusDenied:
                    NSLog(@"用户不允许定位");
                    break;
                    
                default:
                    break;
            }
        }
        
        return NO;
    }
    

    获取定位信息

    startUpdatingLocation,该方法开启后,当位置改变时会在代理函数- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations中更新定位信息

    [self.locationManager startUpdatingLocation];  //开始定位
    [self.locationManager stopUpdatingLocation]; //停止定位
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
      //locations里就是更新出来的定位信息,一般取最后一个值
    }
    

    CLLocation对象属性说明:

     location.altitude:海拔高度,正数表示在海平面之上,而负数表示在海平面之下
     location.verticalAccuracy:海拔高度的精度。为正值表示海拔高度的误差为对应的米数;为负表示altitude(海拔高度)的值无效
     location.horizontalAccuracy:位置的精度(半径)。位置精度通过一个圆表示,实际位置可能位于这个圆内的任何地方。这个圆是由coordinate(坐标)和horizontalAccuracy(半径)共同决定的,horizontalAccuracy的值越大,那么定义的圆就越大,因此位置精度就越低。如果horizontalAccuracy的值为负,则表明coordinate的值无效
     location.speed:速度。该属性是通过比较当前位置和前一个位置,并比较它们之间的时间差异和距离计算得到的。鉴于Core Location更新的频率,speed属性的值不是非常精确,除非移动速度变化很小
    

    当然不一定每次都能定位成功,而定位失败则有几个可能性,定位失败后再失败回调中可以判断出失败原因。当没有定位权限导致定位失败的时候,locationManager依旧会持续进行定位,此时应该手动让其停止

    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
        if(error.code == kCLErrorLocationUnknown) {
            NSLog(@"无法检索位置");
        }
        else if(error.code == kCLErrorNetwork) {
            NSLog(@"网络问题");
        }
        else if(error.code == kCLErrorDenied) {
            NSLog(@"定位权限的问题");
            [self.locationManager stopUpdatingLocation];
            self.locationManager = nil;
        }
    }
    

    获取指南针信息

    [self.locationManager startUpdatingHeading];  //开始检测
    [self.locationManager stopUpdatingHeading]; //停止检测
    
    //指南针信息将在这里回调
    - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    //这里的数值和自带应用指南针显示的一致
      NSLog(@"数值: %f",newHeading.magneticHeading)
    }
    

    地理编码

    将地理位置名(NSString)进行传参,即可获取到CLPlacemark对象,解析该对象即可获取位置信息。先初始化CLGeocoder对象

    _geocoder = [[CLGeocoder alloc] init];
    
    [self.geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
      //解析CLPlacemark即可获取返回信息
      // placemark.name:位置名称
      //placemark.addressDictionary:位置信息,字典
      //placemark.location:位置坐标,不一定和传入参数一致
    }];
    

    反地理编码

    将地理坐标(CLLocation)进行传参

    [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) 
    //一样,一般取最后一位
    }];
    

    后台定位低功耗设置

    后台短时间持续定位
    要在后台定位,首先要在这里将Location updates打钩

    屏幕快照 2018-01-31 16.46.39.png
    这样就可以实现后台定位,但是该方法只能实现后台定位20-30分钟的时间。

    后台永久持续定位
    在定位的时候添加上关键代码

    self.locationManager.pausesLocationUpdatesAutomatically = NO;   //系统是否可以自行中断程序的定位功能
    

    该方法让系统不能够自行关闭程序的定位功能,保证程序一直处于后台定位中,该功能可以参考一款app:Moves

    有一点需要声明:
    定位权限为应用使用期间的时候,程序在后台运行时会在顶部有一条蓝色的信息框
    定位权限为始终的时候,就不会有蓝色框了。

    关于审核

    当程序中有定位的功能时,在提交审核之前要在info文件添加权限那里添加好详细的注释,即告诉用户,我的app要使用您手机的定位功能,请允许我在您使用应用期间(或应用处于后台时)拥有定位权限,如果是后台持续定位,需要在提交审核的时候备注栏上说明详细,后台定位的功能是什么目的,用于什么地方,以及在app介绍中添加“我们将使用您的定位功能”。
    是不是很麻烦,是的,不过当你程序被拒之后会更麻烦。

    我将上面的代码进行了block封装
    github链接

    相关文章

      网友评论

      • 热血足球2016:请问大大如何定位附近的坐标,我看定位只有一个位置,还有这句话怎么理解
        NSTimeInterval locationAge = [[(CLLocation *)[locations lastObject] timestamp] timeIntervalSinceNow];
        Double_Chen:@热血足球2016 你设置定位精度看看
        热血足球2016:就像百度地图定位一样,他会定位第一个是准确的位置,也会定位到旁边的建筑,微信朋友圈发送文字选位置也是这个功能,不知道原生的这个能不能实现,发现代理的那个数组只有一个值,就是本身最准确的定位位置
        Double_Chen:什么叫附近的坐标,定位就定的自身坐标啊;
        开始定位后会持续的回调location对象,只有一个位置是不是获取到定位后马上就停止定位了;
        你这行代码是获取时间戳的值,locations是坐标数组,取最后一个元素的时间戳属性值

      本文标题:iOS CoreLocation的使用及后台持续定位

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