iOS定位服务

最近在做公司内部的一个项目。主要需求很简单,就是每隔N分钟向服务器发送设备的位置,不管此时App是运行在前台还是后台。
这里总结一下使用iOS定位服务的一些关键点和需要注意的地方。

App 的设置

  1. 因为App需要在后台的时候也能不断地获取设备的位置。所以要将Capablities里面的BackgroundMode 设置成Enable。并且勾选其中的Location updates选项。
  2. 在iOS8以后,需要在info.plist里面添加NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription,这两个key都是NSString类型。使用哪个(或者两者都添加)取决于申请定位的权限,这个下文会提到。这个所谓的描述就是当系统提示用户App要使用定位的时候,会加在系统提示的后面,如图。

初始化CLLocationManager

使用iOS定位服务需要引入系统的头文件并且实现CLLocationManagerDelegate的代理。

    #import <CoreLocation/CoreLocation.h>

先来看一下初始化的代码:

-(void) createLocationManager{
    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [_locationManager requestAlwaysAuthorization];
    }
    if ([_locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
        [_locationManager setAllowsBackgroundLocationUpdates:YES];
    }
    _locationManager.pausesLocationUpdatesAutomatically = NO;
}

iOS8以后,系统的定位权限有三种,对应设置里面的总是,永不,和App使用期间。那么根据我们App的需求,我们需要申请“总是”这种权限。相应地,我们要在info.plist里面添加的是NSLocationAlwaysUsageDescription。

    if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
       [_locationManager requestAlwaysAuthorization];
    }

并且在iOS9之后,如果需要在后台保持定位,除了上文所说的在App的setting和info文件里面设置以外,还需要加上下面的代码:

if ([_locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [_locationManager setAllowsBackgroundLocationUpdates:YES];
}

整个初始化完成以后,调用以下API系统就会开始定位了

[_locationManager startUpdatingLocation];

在代理里面实现位置更新的代码

正常来说,完成上面的所有设置,就可以使用iOS系统的定位服务了。
系统会每秒都调用

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations

这个代理方法,我们所要做的就是在这里处理系统返回回来的位置信息。
CLLocation这个类里面包括的一些常用的位置信息有经度、纬度、海拔、速度、精确度等等,根据项目的需求可以对其进行相应的处理。

到这里,最基础的部分已经完成。接下来会探讨一些别的配置。

pausesLocationUpdatesAutomatically属性

贴上一段官网对这个属性的描述:

Allowing the location manager to pause updates can improve battery life on the target device without sacrificing location data. When this property is set to YES, the location manager pauses updates (and powers down the appropriate hardware) at times when the location data is unlikely to change. For example, if the user stops for food while using a navigation app, the location manager might pause updates for a period of time. You can help the determination of when to pause location updates by assigning a value to the activityTypeproperty.

大致的意思就是如果这个属性设置成YES(默认的也是YES),那么系统会检测如果设备有一段时间没有移动,就会自动停掉位置更新服务。这里需要注意的是,一旦定位服务停止了,只有当用户再次开启App的时候定位服务才会重新启动。
这里的一段时间是系统自动判定的,可以通过设置activityTypeproperty这个属性来决定这个时间的长短。
API的意思是,类似导航类的App,系统检验的时间会稍长一点,想运动类的App,就会比导航类的短一点。但是具体时间还是由系统来决定。

DeferredUpdates

默认地,定位服务的代理会每秒钟都更新一次位置,这样对电池的消耗量会特别地大。除了设置pausesLocationUpdatesAutomatically这个属性以外,iOS还提供了DeferredUpdates的机制。

官方API文档:

- (void)allowDeferredLocationUpdatesUntilTraveled:(CLLocationDistance)distance
                                      timeout:(NSTimeInterval)timeout

distance:
The distance (in meters) from the current location that must be travelled before event delivery resumes. To specify an unlimited distance, pass the CLLocationDistanceMaxconstant.

timeout:
The amount of time (in seconds) from the current time that must pass before event delivery resumes. To specify an unlimited amount of time, pass the CLTimeIntervalMax constant.

就是你可以设置让系统每隔多远或者每隔多长时间更新一次位置。注意是“或”的关系,满足一个就会更新。
使用这个方法有很多要注意的地方:

  1. desiredAccuracy必须设置成kCLLocationAccuracyBest
  2. distanceFilter必须设置成kCLErrorDeferredDistanceFiltered
  3. 必须能够使用GPS进行定位(而不仅仅是移动数据或者Wi-Fi)
  4. 非常重要的一点,DeferredUpdates只会出现在设备进入低耗电量的状态,App运行在前台或者设备连接在Xcode上正在调试是不会触发的。(所以不可能在Debug的时候打印Log来检验,要调试的话,需要写一些Log存在本地的数据库)

官网的Example:

-(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 a period of time has passed
  if (!self.deferringUpdates) {
    CLLocationDistance distance = self.hike.goal - self.hike.distance;
    NSTimeInterval time = [self.nextUpdate timeIntervalSinceNow];
    [self.locationManager allowDeferredLocationUpdatesUntilTraveled:distance timeout:time];
    self.deferringUpdates = YES;
  } }
 
-(void)locationManager:(CLLocationManager *)manager
    didFinishDeferredUpdatesWithError:(NSError *)error {
  // Stop deferring updates
  self.deferringUpdates = NO;
 
  // Adjust for the next goal
}

反地理编码

知道了经纬度,有时候我们需要获取这个经纬度对应的详细地址信息,示例如下:

CLGeocoder *revGeo = [[CLGeocoder alloc] init];
[revGeo reverseGeocodeLocation:location
                 completionHandler:^(NSArray *placemarks, NSError *error) {
                     if (!error && [placemarks count] > 0)
                     {
                         NSDictionary *dict =
                         [[placemarks objectAtIndex:0] addressDictionary];
                         NSArray *formattedLines = [dict objectForKey:@"FormattedAddressLines"];
                         NSString *formattedAddress = formattedLines[0];
                         NSLog(@"address is %@",formattedAddress);
                     }else{
                         NSLog(@"ERROR: %@", error);
                     }
                 }];

关于坐标系的问题

最后讲一下关于坐标系的问题。
世界通用的坐标系是WGS坐标系,中国国测局的坐标系是GCJ,百度有自己的坐标系。
同样的经纬度应用在不同的坐标系会有所偏差,在Github上面有一个库可以实现不同坐标系之间的转化:
https://github.com/TinyQ/TQLocationConverter
系统返回的自然是根据WGS定位的。如果使用百度SDK获取的就是Baidu坐标系的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容