Location and Maps Programing Guide(一)

关于定位服务和地图

在你的应用中使用基于位置信息的服务可以很好的使用户保持于周围世界的连接.当你为了特殊的目的(比如导航)或者娱乐,使用基于位置信息的服务可以整体增强用户的体验.
基于位置信息服务包含两个方面: 定位服务和地图. 定位服务通过 Core Location framework来提供,它定义了一些Objective-C的接口来获取用户的location(位置)和heading(设备指向的方向). 地图是通过Map Kit framework来提供,它支持显示和标注,就像iOS应用中自带的地图应用一样.(为了使用地图服务,你必须打开Xcode工程中得地图能力, Target->Capabilities)

总览

通过将地理数据放置在应用中,你可以将用户放在周围的环境中,并连接周围的人.
因为地图和定位服务在iOS和OS X 都可用,基于定位的应用的代码在两个平台上是差不多的. 不同的是UI相关的代码(比如 在iOS中使用UIView,而在OS X 中使用 NSView) 和一些功能的支持(比如方向服务只在iOS中有).

位置服务为应用提供了地图环境

知道用户的地理位置可以提高用户的体验,甚至是应用的核心功能.有导航功能的应用使用位置服务去监听用户的位置变化和更新,其他使用位置服务的应用可以提供周围用户社交功能.

iBeacon传送器增强了用户定位体验

iBeacon发射机提供一种方法来创建和监测信号,使用蓝牙低能耗无线技术宣传某些识别信息. 在应用中使用 Core Location监听在低能耗蓝牙信号塔信号范围内UUID相同的信号. 当一个信号在用户设备范围内,应用还可以监听与信号的距离.
你可以使用这些信号来发送广告来增强用户在特殊位置的体验.比如说一个博物馆的应用可以监听周围博物馆重要的展览.当用户处理一个展览的时候,应用可以使用相对距离最为一个线索来提供更多的关于这个展览的信息.
因为信号塔广告使用的时低能耗蓝牙传输,你可以将任何一部iOS支持蓝牙的设备接入信号范围.

Heading 信息表示着用户当前的方向

Heading服务通过基础的定位服务提供了更多的设备方向的精确信息.
最为显著使用这个服务的应用是陀螺仪,但是你也可以使用在增强现实,游戏和地图导航上.即使设备上没有磁力计–获取heading信息的硬件,
也可以获取应用需要的航线和速度信息.

地图支持导航,并显示地理相关的内容

地图是帮助用户通过可视化的 方式去理解地理数据.例如:地图可以在一个范围内显示卫星数据,或者将地图放在一个有角度和三维数据的3D视图.你可以将地图框架中得标准视图放在你的应用中去展示相关地理位置的信息.另外这个框架允许我们自己在地图上展示相关数据,滚动地图和截取当前位置截屏.

线路应用给用户提供方向

一个线路应用可以从地图应用中获取坐标信息,然后提供给用户点到点的路线. 一个提供导航的应用可以声明自己是一个线路应用,添加了额外的开车或走路的方向,线路应用也支持其他类型的交通,如出租车,飞机和其他公共交通.

地区搜索

用户通过描述信息找到位置,比如一个名字, 地址或商业类型.使用地图框架可以通过用户的输入搜索并显示在地图中.

获取用户位置

应用为了多种目标使用位置信息,从社交网络到逐向道路导航服务.应用通过Core Location framework来获取数据.这个框架提供了几种用户获取用户位置和监听设备位置的方式:

  • 显著位置变化的位置服务,使用了一种低功耗的方式去获取当前位置和接受位置变化的通知.
  • 标准定位服务提供了高可配置的方式去获取位置和接受位置变化通知.
  • 区域监控允许您监控区域边界过境点定义的地理区域和蓝牙低能地区的灯塔。(信标区域监测只能在iOS).
在iOS应用上使用当前位置信息服务

如果你的iOS应用 ,如果你的应用需要在适当的时候使用位置信息,在应用的Info.plist文件中加入 UIRequiredDeviceCapabilities键. 苹果应用商店使用这个值去阻止那些没有功能的设备下载应用.
UIRequiredDeviceCapabilities 的值是一个包含相关功能字符串的数组. 两个字符串与定位服务有关:
- location-services,通常的定位服务
- gps, 只通过硬件提供精准的位置

重要:如果你的应用使用了定位服务,但是可以正常的在没有定位服务的情况下完成操作,就不要包含UIRequiredDeviceCapabilities键值

获取用户当前位置

Core Location framework可以让我们获取用户设备的当前位置信息并用于我们的应用中.框架报告位置信息取决于你的代码是如何配置这个服务的,并且当收到新的数据提供周期性的更新.
两个服务可以给我们当前用户位置信息:

  • 标准的定位服务是可配置的,通常,可以根据指定的精确度级别来获取位置数据和监听位置变化.
  • 重大的位置变化服务只在设备有很大的位置变化的时候才发出更新,比如500米或更多.
    收集位置信息是一种敏感操作.对于大多数应用,通常会初始化获取一个位置,然后周期性的获取更新.不管获取的位置信息在你的应用中是否重要,你应该选择合适的位置服务,合理的使用它,避免浪费设备电量:
  • 如果你的应用即使在后台也需要保持监听位置服务,则使用标准的位置服务,设置在Info,plist文件中设置UIBackgroundModes的值为location,这样可以在后台运行并接受更新.而且要确定 location manager的pausesLocationUpdatesAutomatically属性设置为YES. 比如需要这种类型的服务是运动类的,导航类的等.
  • 如果GPS级别的精确度适合你的应用,而且不需要持续的追踪位置,则使用重大位置变化服务. 这个服务可以节约设备电量, 因为他不是实时追踪位置信息,而且只在使用应用的时候服务.
判断位置服务是否可用

这里有一些情况使得位置服务不可用:
- 用户在系统设置里面关闭了位置服务功能
- 用户对某个应用关闭的位置服务功能
- 设备在飞行模式和没有电量启动

基于这些原因, 建议你在开始使用位置服务或者重大变化位置服务之前保持调用类 CLLocationManager 的类方法locationServicesEnabled来判断位置服务功能是否开启. 如果位置服务没有开启,而开始定位,系统会提示用户是否要开启位置服务,比如用户会主动关闭服务,所以提示会不友好.

开始标准位置服务

标准位置服务是最通用的方式获取用户位置信息的方式,因为他在iOS和OS X都可用.在使用服务之前,你需要配置位置服务的精确度和位置报告需要的移动的距离. 当我们开启服务后,服务会通过特殊参数去决定硬件的打开和报告位置时间给应用.因为服务考虑这些参数,需要应用更细粒度的去控制位置事件的传递.标准定位服务的精确度是被导航应用或其他需要高精度位置的应用需要的.因为这个服务通常需要设备硬件开启位置追踪一段时间,但会导致高电量使用.

使用标准位置服务,创建一个CLLocationManager类的实例,配置它的desiredAccuracydistanceFilter属性.为了能开始接受位置通知,指定一个代理对象,然后调用 startUpdatingLocation方法.当位置数据可用的时候,CLLocationManager会通过代理方法通知给代理着. 如果你一位置更新已经被传递了,我们可以通过CLLocationManager对象获取当前位置的更多数据,要想停止更新位置,调用stopUpdatingLocation方法.

创建方法如下:

 - (void)startStandardUpdates
  {
      // Create the location manager if this object does 
      // already have one.
      if (nil == locationManager)
          locationManager = [[CLLocationManager alloc] init];
      locationManager.delegate = self;
      locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
      // Set a movement threshold for new events.
      locationManager.distanceFilter = 500; // meters
      [locationManager startUpdatingLocation];
  }
开始使用重大变化位置服务

这个服务提供了足以使大多数应用使用的精确度,而且比标准位置服务更省电.这个服务使用Wi-Fi来判断用户的位置和报告位置,使用系统来管理用电,这样会更好.这个服务也可以唤醒被挂起或未运行的应用来传递位置事件.
使用服务, 创建一个CLLocationManager实例,设置代理者,调用startMonitoringSignificantLocationChanges方法,同样,如果位置数据已经被传递出来,我们可以通过CLLocationManager实例对象的属性来获取更多的信息而不用等待新位置事件.
下面是代码示例:

- (void)startSignificantChangeUpdates
  {
      // Create the location manager if this object does not
      // already have one.
      if (nil == locationManager)
          locationManager = [[CLLocationManager alloc] init];

      locationManager.delegate = self;
      [locationManager startMonitoringSignificantLocationChanges];
  }

停止重大变化位置服务需要调用stopMonitoringSignificantLocationChanges方法

如果我们保持重大变化位置服务持续开启的话,如果我们的应用被挂起或终结,这个服务会在有线的位置信息到达的时候唤醒我们的应用.在被唤醒期间,应用被放置在后台,我们有一点时间(大约10秒)去重启位置服务和处理位置数据.因为应用在后台,只能做一些小工作和避免阻止事件返回. 如果是那样,应用会被终结.如果应用需要更多的时间处理事件, 可以请求后台执行时间,调用UIApplication类的方法beginBackgroundTaskWithName:expirationHandler

如果用户关闭了后台应用刷新的功能, 重大变化位置服务是不能唤醒应用的.而且,当后台应用刷新的功能关闭后,即使应用在前台也不能收到位置更新的事件了

从一个位置服务收到位置数据

不论使用标准位置服务还是重大变化位置服务,收到位置数据的方式是一样的.从OS X10.9和iOS6以后,location manager 通过代理方法locationManager:didUpdateLocations报告位置数据,在以前的版本,使用locationManager:didUpdateToLocation:fromLocation方法.
如果更新位置失败,会调用locationManager:didFailWithError代理方法.
下图显示代理方法收到位置数据.因为location manager 有时候会返回缓存的位置事件,推荐我们检查每一个位置事件的时间戳来判断是否为新位置数据(它可能要花上几秒钟的时间获得一个粗略的位置固定,所以旧的数据只是作为一种反映了最后的位置–意思就是系统需要一点事件来获取新数据,返回缓存的数据是为了保持数据报告).在这个例子中,只会处理15秒内的新位置数据.

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {
    // If it's a relatively recent event, turn off updates to save power.
   CLLocation* location = [locations lastObject];
   NSDate* eventDate = location.timestamp;
   NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
   if (abs(howRecent) < 15.0) {
      // If the event is recent, do something with it.
      NSLog(@"latitude %+.6f, longitude%+.6f\n",    location.coordinate.latitude,location.coordinate.longitude);
    } 
}

除了位置信息的时间戳,我们也可以使用数据 的精确度来判断是否使用这次位置事件.当收到更精确的数据,服务会返回更多的事件.丢弃低精度的事件,意味着应用可以减少浪费在不能用的数据上.

知道何时开始位置服务

应用应该在使用位置服务之前才开始开启服务. 而不要在应用已启动就开启位置服务. 另外,我们应该让用户知道我们为什么使用位置服务.用户知道应用何时开启位置服务, 因为第一次开启服务会提示用户授权.直到展示了使用位置服务功能的一面给用户,与用户建立信任关系.另一个建立信任的方式是在Info.plist文件中添加NSLocationUsageDescription键, 值为描述为何使用位置服务.

如果我们追踪地区或者使用重大变化位置服务,有一些情况我们必须在应用启动的时候开启服务. 使用这些服务的应用可以被终结然后当新位置事件到达后唤醒应用. 然而,应用自己重启的, 位置服务是不会自动重启的. 当应用重启是被位置服务重启的, 会在应用代理方法 application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:的参数中会带有UIApplicationLaunchOptionsLocationKey键值对.这里面的值是新位置信息的数据.为了获取这些数据,我们必须创建一个新的CLLocationManager对象,重启位置服务,随后被挂起的更新会通过代理方法传递.

在后台获取位置事件(限iOS)

iOS支持应用在挂起或未运行的时候传递位置事件.位置事件在后台传递给那些没有损害用户的应用,所以配置我们的应用去接受位置事件来提供给用户有形的好处.例如全程导航应用需要一直追踪用户位置信息然后可以在下一个转弯处通知用户.

我们可以有许多选择去获取后台位置服务,每种服务都有好处和坏处,因为取决于电力消耗和定位精确度. 如果可以, 应用可以使用重大变化位置服务,它会使用Wi-Fi来决定用户的位置并且可以节约电量.但是你的应用需要好精度的位置数据,我们可以配置应用为后台应用并使用标准定位服务.

在后台使用标准位置服务

如果iOS应用需要持续的位置更新服务,可以在后台使用标准位置服务. 开启后台服务需要在Xcode项目Capabilities中开启Background Modes,设置开启Location updates mode. 我们写得标准位置服务的代码不需要改变.

系统会传递位置事件给应用,不论应用是在前台,后台还是挂起.如果应用挂起, 系统会唤醒应用,传递位置事件给应用,然后立即再次挂起应用.如果应用在后台运行, 应用有一点时间去处理位置事件.

当位置服务开启,设备必须开启才能获取新位置数据.保持位置服务运行会降低电池寿命,我们应该在不使用位置数据的时候关闭位置服务.

如果我们必须在后台使用位置服务,我们可以帮助 Core Location来为用户设备保持电池的寿命,通过以下几步来设置 location manager 对象:

  • 保证 location manager的pausesLocationUpdatesAutomatically属性设置为YES.当设置为YES的时候,Core Location会在合适的时候停止服务,比如用户没有移动
  • 给location manager的activityType属性设置适当的值.这个值可以帮助location manager 知道何时是可以安全的停止服务的.一个提供全程手机导航的应用设置了值为CLActivityTypeAutomotiveNavigation,会导致location manager在用户没有在一段时间内移动很大距离的时候关闭服务.
  • 调用allowDeferredLocationUpdatesUntilTraveled:timeout去延迟一段时间或距离来传递位置事件.

当location manager 暂停了服务,它会通知代理方法locationManagerDidPauseLocationUpdates.当location manager恢复服务,会通知代理方法locationManagerDidResumeLocationUpdates.我们可以使用这些方法来适应应用功能.比如,当位置服务暂停了,我们可能需要保存数据等.一个导航应用可能需要提示用户导航暂停等.

提示: 如果应用被系统或用户终结掉,系统不会在新位置事件到达的时候重启我们的应用.在位置服务恢复之前用户必须手动重启我们的应用. 让我们的应用自动重启的唯一方式是使用地区监视或重大变化位置服务.

但是用户为某个应用关闭或关闭全部后台刷新功能,系统不会重启应用,即使使用了地区监视或重大变化位置服务. 当后台刷新功能关闭后,地区监视或重大变化位置服务不会发送位置事件,即使应用在前台.但是当用户重新开启后台刷新服务后,Core Location会重新保存后台服务,包括之前注册的地区

当应用在后台的时候推迟位置事件更新

在iOS6以后,我们在后台可以推迟位置事件更新.当应用使用推迟的位置数据没有问题的时候,推荐我们使用这个功能.比如一个健康应用 监视用户徒步数据,可以在用户行走了一段距离后或时间后更新一次.推迟更新可以节约设备电量.因为推迟更新服务需要GPS硬件的支持,确保在使用之前调用类CLLocationManager的类方法deferredLocationUpdatesAvailable来判断是否支持.
调用类CLLocationManager的方法allowDeferredLocationUpdatesUntilTraveled:timeout开始推迟位置更新服务.重复调用allowDeferredLocationUpdatesUntilTraveled:timeout来设置推迟位置更新服务.

实例代码:

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {
   // Add the new locations to the hike
   [self.hike addLocations:locations];
   // Defer updates until the user hikes a certain distance
   // or when a certain amount of time has passed.
   if (!self.deferringUpdates) {
      CLLocationDistance distance = self.hike.goal - self.hike.distance;
      NSTimeInterval time = [self.nextAudible timeIntervalSinceNow];
      [locationManager allowDeferredLocationUpdatesUntilTraveled:distance
     timeout:time];
   self.deferringUpdates = YES;
} }

当达到了allowDeferredLocationUpdatesUntilTraveled:timeout的设置条件,location manager会调用locationManager:didFinishDeferredUpdatesWithError方法通知代理者.只要调用一次allowDeferredLocationUpdatesUntilTraveled:timeout开始方法, 就是被通知一次结束方法locationManager:didFinishDeferredUpdatesWithError.当位置事件传递完会调用locationManager:didUpdateLocations. 我们可以停止推迟位置服务,调用CLLocationManager的类方法stopUpdatingLocation, 然后 代理方法locationManager:didFinishDeferredUpdatesWithError会调用,表示服务停止.

保护电池的小贴士

在iOS设备上获取位置信息需要很多电量.因为大多数应用不需要一直运行位置服务.当不需要位置服务的时候关闭它是最简单的办法:
- 当应用不需要位置服务的时候关闭它们.
- 尽可能的使用重大变化位置服务代替标准位置服务
- 在不损害应用的情况下使用低精度的值获取位置事件
- 如果在一段时间内精确度不在增长,关闭服务
- 在标准位置服务中使用合适的activity type
- 允许location manager推迟传递位置事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值