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閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容