CoreLocation
是iOS中一个提供设备位置的框架。通过这个框架可以实现定位处理,获取位置数据。位置数据通常包括经度,纬度,海拔信息等。
iOS8系统下使用定位服务必须在info.plist
文件中添加两个变量NSLocationAlwaysUsageDescription
和NSLocationWhenInUseUsageDescription
,这两个Key的值,将分别用于描述应用程序始终使用和使用期间使用定位的说明。
NSLocationAlwaysUsageDescription
String 应用程序始终使用定位服务
NSLocationWhenInUseUsageDescription
String 使用应用程序期间,可以使用定位服务
CLLocationManager属性和方法
属性名 | 描述 |
---|---|
location:CLLocation | 位置 |
desiredAccuracy:CLLocationAccuray | 位置精度 |
func startUpdatingLocation() | 开启更新位置 |
func stopUpdatingLocation() | 停止更新位置 |
func startUpdatingHeading() | 开启更新方向 |
func stopUdatingHeading() | 停止更新方向 |
精度的六种选择
desiredAccuracy属性 | 描述 |
---|---|
let kCLLocationAccuracyBestForNavigation: CLLocationAccuracy | 精度最高,一般用于导航 |
let kCLLocationAccuracyBest: CLLocationAccuracy | 精度最佳 |
let kCLLocationAccuracyNearestTenMeters: CLLocationAccuracy | 精确度10米内 |
let kCLLocationAccuracyHundredMeters: CLLocationAccuracy | 精确度100米内 |
let kCLLocationAccuracyKilometer: CLLocationAccuracy | 精确度1000米内 |
let kCLLocationAccuracyThreeKilometers: CLLocationAccuracy | 精确度3000米内 |
对于管理器启动更新后,更新将不断传递给位置管理器委托,直到更新结束。我们无法直接控制位置管理器更新的频率,但可以用位置管理器的distanceFilter
属性进行间接控制。在启动更新前设置属性distanceFilter
,它指定设备移动多少米后才将另一个更新发给委托。定位要求的精度越高、属性distanceFilter
的值越小,应用程序耗电量就越大。他的单位是米,我们可以直接使用整型数字来设置这个距离.
locationManager.distanceFilter = 200
用户授权
发出授权申请,设备会弹出提示,请求用户允许使用定位服务。代码如下:
locationManager.requestAlwaysAuthorization()
通过didChangeAuthorizationStatus
代理方法,可以获取设备是否允许使用定位服务,代码如下
func locationManager(_ manager: CLLocationManager,
didChangeAuthorizationStatus status: CLAuthorizationStatus){
if status == .NotDetermined || status == .Denied{
//允许使用定位服务
//开始启动定位更新服务
locationManager.startUpdatingLocation()
print("开始定位")
}
}
startUpdatingLocation
方法启动定位管理,如果我们不需要更新定位时,可以通过stopUpdatingLocation
方法来关闭定位管理,这样可以节省电量。
locationManager.stopUpdatingLocation()
对于委托类CLLocationManagerDelegate
最常用的方法是:
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation])
定位改变时委托执行这个方法,可以得到新位置,旧位置。location数组里会有前后位置的经度纬度坐标值。
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]){
var currlocation:CLLocation
//获取最新坐标
currlocation = locations.last as! CLLocation
//获取经度
currlocation.coordinate.longitude
//获取纬度
currlocation.coordinate.latitude
//获取海拔
currlocation.altitude
}
CLLocation对象包含定位点的相关位置数据,主要有经度、纬度、海拔信息、可以通过属性和方法来获取。
CLLocation属性及方法
属性名 | 功能 |
---|---|
var coordinate: CLLocationCoordinate2D { get } | 位置的纬度和经度 |
var altitude: CLLocationDistance { get } | 位置海拔 |
var horizontalAccuracy: CLLocationAccuracy { get } | 位置的水平精度 |
var verticalAccuracy: CLLocationAccuracy { get } | 位置垂直精度 |
var speed: CLLocationSpeed { get } | 位置的方向 |
var course: CLLocationDirection { get } | 位置的速度 |
func distanceFromLocation(_ location: CLLocation) -> CLLocationDistance | 两个位置之间的距离 |
使用`func locationManager(_ manager: CLLocationManager,
didUpdateHeading newHeading: CLHeading)`可以获取到设备移动的方向。参数`newHeading`是一个CLHeading对象。CLHeading通过一组属性来提供航向读数:
magneticHeading
和trueHeading
。这些值的单位为度。类型为CLLocationDirection
,即双精度浮点数。这意味着:
如果航向为0.0,则前进方向为北
如果航向为90.0,则前进方向为东
如果航向为180.0,则前进方向为南
如果航向为270.0,则前进方向为西
magneticHeading
和trueHeading
分别表示磁性航向,和真实航向。如果位置服务被关闭了,GPS和WIFI就只能获取磁场航向。只有打开位置服务,才能获取真实航向。
需要注意,在使用代理前,需要开启更新方向:
locationManager.startUpdatingHeading()
CLHeading属性
属性名 | 描述 |
---|---|
magneticHeading | 位置的磁极方向 |
trueHeading | 位置的真实方向 |
headingAccuracy | 方向经度 |
timestamp | 时间戳 |
description | 获取方向数据 |
CLError
当定位失败时就会调用委托方法
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
//错误处理 当地位出错时调用
if let clerr = CLError(rawValue: error.code){
}
}
//CLError 是一个每枚举类型
public enum CLError : Int {
case LocationUnknown // location is currently unknown, but CL will keep trying
// 目前未知,请努力获取
case Denied // Access to location or ranging has been denied by the user
// 获取位置功能被拒绝使用
case Network // general, network-related error
//网络错误
case HeadingFailure // heading could not be determined
//获取的位置标题信息,不能确定
case RegionMonitoringDenied // Location region monitoring has been denied by the user
//位置区域已被用户监测
case RegionMonitoringFailure // A registered region cannot be monitored
//监测器不能注册
case RegionMonitoringSetupDelayed // CL could not immediately initialize region monitoring
//不能初始化检测器
case RegionMonitoringResponseDelayed // While events for this fence will be delivered, delivery will not occur immediately
//区域检测器响应延迟
case GeocodeFoundNoResult // A geocode request yielded no result
//地理编码无结果
case GeocodeFoundPartialResult // A geocode request yielded a partial result
//地理编码请求得到部分结果
case GeocodeCanceled // A geocode request was cancelled
//地理编码 请求被取消
case DeferredFailed // Deferred mode failed
//推迟模式失败
case DeferredNotUpdatingLocation // Deferred mode failed because location updates disabled or paused
//由于位置更新失败或者暂停,推迟模式失败
case DeferredAccuracyTooLow // Deferred mode not supported for the requested accuracy
//推迟模式不支持经度要求
case DeferredDistanceFiltered // Deferred mode does not support distance filters
//推迟模式无法支持距离滤波器
case DeferredCanceled // Deferred mode request canceled a previous request
//推迟模式被取消
case RangingUnavailable // Ranging cannot be performed
//无法进行测距
case RangingFailure // General ranging failure
//通用测距故障
}
更多代理的方法请看文档。
地理信息反编码
通过Core Location类得到的地位信息都是以经度和纬度等表示的地理信息。一般都需要反编码城一个地址。
这就需要CLGeocoder
类来实现地理信息反编码
iOS9新特性 更灵活的后台定位(摘自)
请求后台定位权限:
方法一
// 1. 实例化定位管理器
_locationManager = [[CLLocationManager alloc] init];
// 2. 设置代理
_locationManager.delegate = self;
// 3. 定位精度
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
// 4.请求用户权限:
//分为:
//⓵只在前台开启定位
//⓶在后台也可定位,
//注意:建议只请求⓵和⓶中的一个,如果两个权限都需要,只请求⓶即可,
//⓵⓶这样的顺序,将导致bug:第一次启动程序后,系统将只请求⓵的权限,⓶的权限系统不会请求,只会在下一次启动应用时请求⓶
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
//[_locationManager requestWhenInUseAuthorization];//⓵只在前台开启定位
[_locationManager requestAlwaysAuthorization];//⓶在后台也可定位
}
// 5.iOS9新特性:将允许出现这种场景:同一app中多个location manager:一些只能在前台定位,另一些可在后台定位(并可随时禁止其后台定位)。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
_locationManager.allowsBackgroundLocationUpdates = YES;
}
// 6. 更新用户位置
[_locationManager startUpdatingLocation];
对应的 Info.plist 的XML源码是:
<key>NSLocationAlwaysUsageDescription</key>
<string>请求后台定位权限</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
方法二:
在对应 target 的 Capabilities -> Background Modes -> 开启 Location Updates
例子:
typealias CoreLocationdelegate = ViewController
extension CoreLocationdelegate:CLLocationManagerDelegate{
func configLocation(){
//1 the location manager
let locationManager = CLLocationManager()
//2 setting the desired accuracy
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
//3 setting the distance filter
locationManager.distanceFilter = 1000
//4 getting permission to use location services
locationManager.requestAlwaysAuthorization()
//5 starting the location manager
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
//获取设备是否允许使用定位服务
if status == CLAuthorizationStatus.Denied || status == CLAuthorizationStatus.NotDetermined{
locationManager.requestAlwaysAuthorization()
}else{
//允许使用定位服务的话,开启定位服务更新
locationManager.startUpdatingLocation()
//开启方向更新服务
locationManager.startUpdatingHeading()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
//获取最新的坐标
let theLocation = locations.last
//获取纬度
let latitude = theLocation?.coordinate.latitude
//获取经度
let longitude = theLocation?.coordinate.longitude
//获取海拔
let altitude = theLocation?.altitude
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
//错误处理 当地位出错时调用
if let clerr = CLError(rawValue: error.code){
}
}
func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
//可以获取设备移动的方向
}