iOS CoreLocation的使用及后台持续定位
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打钩
这样就可以实现后台定位,但是该方法只能实现后台定位20-30分钟的时间。
后台永久持续定位
在定位的时候添加上关键代码
self.locationManager.pausesLocationUpdatesAutomatically = NO; //系统是否可以自行中断程序的定位功能
该方法让系统不能够自行关闭程序的定位功能,保证程序一直处于后台定位中,该功能可以参考一款app:Moves
有一点需要声明:
定位权限为应用使用期间的时候,程序在后台运行时会在顶部有一条蓝色的信息框
定位权限为始终的时候,就不会有蓝色框了。
关于审核
当程序中有定位的功能时,在提交审核之前要在info文件添加权限那里添加好详细的注释,即告诉用户,我的app要使用您手机的定位功能,请允许我在您使用应用期间(或应用处于后台时)拥有定位权限,如果是后台持续定位,需要在提交审核的时候备注栏上说明详细,后台定位的功能是什么目的,用于什么地方,以及在app介绍中添加“我们将使用您的定位功能”。
是不是很麻烦,是的,不过当你程序被拒之后会更麻烦。
我将上面的代码进行了block封装
github链接