iOS

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

2018-01-31  本文已影响1243人  Double_Chen

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

上一篇下一篇

猜你喜欢

热点阅读