一、CLLocationManager权限相关方法
/** 查看设备的定位功能是否已经开启 */
+ (BOOL)locationServicesEnabled API_AVAILABLE(ios(4.0), macos(10.7));
/** 是否可以获得设备的指向(有磁力计的设备可以获得设备的指向) */
+ (BOOL)headingAvailable API_AVAILABLE(ios(4.0), macos(10.7)) API_UNAVAILABLE(watchos, tvos);
/** 重要位置更改跟踪。此方法指示设备是否能够仅基于重要位置更改报告更新,这种功能提供了巨大的功率节省的应用程序,要跟踪用户的大致位置,不需要高度准确的位置信息。 */
+ (BOOL)significantLocationChangeMonitoringAvailable API_AVAILABLE(ios(4.0), macos(10.7)) API_UNAVAILABLE(watchos, tvos);
/** 确定设备是否支持指定区域的跟踪 */
+ (BOOL)isMonitoringAvailableForClass:(Class)regionClass API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvos);
/** 是否可以获取这个区域内所有iBeacon的信息 */
+ (BOOL)isRangingAvailable API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(watchos, tvos);
/* 用户的定位授权状态*/
+ (CLAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(4.2), macos(10.7));
// 定位的类型,普通\汽车导航\步行导航\其它导航\空运导航
@property(assign, nonatomic) CLActivityType activityType API_AVAILABLE(ios(6.0), watchos(4.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(tvos);
// 移动了多大距离更新位置信息
@property(assign, nonatomic) CLLocationDistance distanceFilter;
// 定位的精度, 精度越高越耗电
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
// 使用这个属性可以控制是否可以后台更新位置。前提是需要自己在info.plist文件中配置对应的key
// NSLocationWhenInUseUsageDescription 或者NSLocationAlwaysUsageDescription
@property(assign, nonatomic) BOOL allowsBackgroundLocationUpdates API_AVAILABLE(ios(9.0), watchos(4.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(tvos);
// 在Always authorization下可以使用这个来控制是否显示状态栏上的定位图标
@property(assign, nonatomic) BOOL showsBackgroundLocationIndicator API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(watchos, tvos);
// 是否允许系统在位置长时间没移动的时候暂停定位功能。
// 如果是允许的,那么在暂停时会调用代理方法 -locationManagerDidPauseLocationUpdates:
// 暂停之后需要自己手动唤起重新定位,方法是添加一个关于位置的本地通知,当位置发生移动后触发通知,此时去重新开始定位
@property(assign, nonatomic) BOOL pausesLocationUpdatesAutomatically API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(watchos, tvos);
二、开始使用定位
- 如果设备未开启定位服务,提示用户去设置里面开启。
- 判断权限:[CLLocationManager authorizationStatus]。
- 如果是kCLAuthorizationStatusNotDetermined,说明是未向用户请求权限,需要自己请求权限,这个时候系统会弹出警示框让用户选择,用户选择的结果在代理方法回调locationManager:didChangeAuthorizationStatus:。
请求权限的方法:
- (void)requestWhenInUseAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos);
- (void)requestAlwaysAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(tvos);
// 请求权限必须要自己手动在info.plist中添加对应的键值对
1. NSLocationAlwaysUsageDescription // 申请一直使用定位权限,前台/后台
2. NSLocationWhenInUseUsageDescription // 申请使用应用期间的定位权限
3. 需要注意的是,添加以上两个key的同时,还需要添加下面这个key
NSLocationAlwaysAndWhenInUseUsageDescription
所有key,都要详细说明申请该权限的原因,否则会因为权限问题审核悲剧
- 如果是拒绝的权限,提示用户去设置中修改。
- 如果是可以使用的权限,那么初始化CLLocationManager对象, 设置属性,调用定位方法-startUpdatingLocation开始进行定位。
// 定位的方法
- (void)startUpdatingLocation API_AVAILABLE(watchos(3.0)) API_UNAVAILABLE(tvos);
- (void)stopUpdatingLocation;
- (void)requestLocation API_AVAILABLE(ios(9.0), macos(10.14));
// 重大位置更新,当开始了这个位置监控后,APP处于前台后台都能接收到位置更新的代理回调,
// 且如果APP被终止了,当用户位置进入新的重要位置点时,系统会重新在后台打开APP, 打开时在didFinishLaunchingWithOptions:方法里面的options有键UIApplicationLaunchOptionsLocationKey,
// 此时你可以重新初始化CLLocationManager对象并开始这个方法
- (void)startMonitoringSignificantLocationChanges API_AVAILABLE(ios(4.0), macos(10.7)) API_UNAVAILABLE(watchos, tvos);
- (void)stopMonitoringSignificantLocationChanges API_AVAILABLE(ios(4.0), macos(10.7)) API_UNAVAILABLE(watchos, tvos);
// 监控进入或者离开区域,最多可以注册20个区域。一旦开启,效果跟上面的重大位置更新一样。
- (void)startMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(5.0), macos(10.8)) API_UNAVAILABLE(watchos, tvos);
// 设置使用GPS高精度的定位,并且是延迟达到一定距离或者时间才触发位置更新回调
- (void)allowDeferredLocationUpdatesUntilTraveled:(CLLocationDistance)distance
timeout:(NSTimeInterval)timeout API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(watchos, tvos);
三、CLLocationManagerDelegate代理方法
关键的几个代理方法如下:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_AVAILABLE(ios(4.2), macos(10.7));
// locations里面放着不同时间点定位的位置,最后一个是最新定位的位置
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations API_AVAILABLE(ios(6.0), macos(10.9));
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
四、定位不准确问题
Core Location may report a cached value to your delegate immediately after you start the service, followed by a more current value later. Check the time stamp of any data objects you receive before using them.
在刚开始定位时,CLLocationManagerDelegate方法里面的参数有可能是系统的一个缓存值,在使用的时候需要对参数的时间戳进行判断。
- 在刚刚开始定位时,系统返回的一个位置通常是缓存的一个导致定位不准确
对于这个问题,官方给出的解决方案是比对location的时间戳,大于10s则不处理
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations {
NSDate* newLocDate = locations.lastObject.timestamp;
NSTimeInterval interval = [newLocDate timeIntervalSinceNow];
if( abs(interval) < 10 ) {// 10s内的定位是可以使用的
self.location = newLocation;
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
[ ... ];
} else {
//skip the cache data(跳过缓存值)
}
}
- 定位的位置不可用,如果水平精度小于0时,数据错误,不可用。
/* 当定位成功后,如果horizontalAccuracy大于0,说明定位有效
horizontalAccuracy,该位置的纬度和经度确定的圆的中心,并且这个值表示圆的半径。负值表示该位置的纬度和经度是无效的。
*/
if(location.horizontalAccuracy < 0) return;
- 有时定位不准确,需要用户手动选择位置,这时就需要集成地图定位功能了,集成百度地图或高德地图的SDK都可以。
五、Demo
总结写出来的一个类,可以拿去用,在这个基础上根据自己需要修改应该会更高效
demo地址
网友评论