バックグラウンドで位置情報を取得する（CoreLocation::CLLocationManager）

# バックグラウンドで位置情報を取得する

## 標準位置情報サービス準備

Info.plistのRequired device capabilitiesにlocation-servicesとgps追加
Info.plistのInformation Property ListにNSLocationAlwaysUsageDescriptionを追加して、許可を求めるダイアログに表示する文字列を設定
Button * 2（開始・終了用）をストーリーボードに配置し、Outlet・Actionを作成してViewController.swiftに以下のコードを記述

```swift:ViewController.swift
import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    var myLocationManager: CLLocationManager!
    
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var stopButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let status = CLLocationManager.authorizationStatus()
        if status == CLAuthorizationStatus.Restricted || status == CLAuthorizationStatus.Denied {
            return
        }
        
        myLocationManager = CLLocationManager()
        myLocationManager.delegate = self
        
        if status == CLAuthorizationStatus.NotDetermined {
            myLocationManager.requestAlwaysAuthorization()
        }
        
        if !CLLocationManager.locationServicesEnabled() {
            return
        }
        
        myLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        myLocationManager.distanceFilter = 100
    }

    @IBAction func onClickStartButton(sender: UIButton) {
        myLocationManager.startUpdatingLocation()
    }
    
    @IBAction func onClickStopButton(sender: UIButton) {
        myLocationManager.stopUpdatingLocation()
    }
    
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let lastLocation = locations.last
        if let last = lastLocation {
            let eventDate = last.timestamp
            if abs(eventDate.timeIntervalSinceNow) < 15.0 {
                if let location = manager.location {
                    print("緯度：\(location.coordinate.latitude)")
                    print("経度：\(location.coordinate.longitude)")
                }
            }
        }
    }
    
    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("error")
    }
```

詳しくは[定期的に位置情報を更新する](http://qiita.com/shngt/items/ee3c1d283acd5a85fa63)を参照

## バックグラウンドの位置情報取得許可

Info.plistのInformation background modesにRequired background modesを追加
画面左のファイル一覧からプロジェクト（一番上のルート）を選択し、Capabilitiesタブ->Background ModesのLocation updatesをチェック

## 電池消費を抑える設定

> 位置情報サービスが有効であれば、iOSは位置情報ハードウェアに電力を供給し、常に新しいデータを収集することになります。すると電池が消耗するので、位置情報データが必要なければ常に、サービスを停止するようにしてください。

- pausesLocationUpdatesAutomatically

ユーザが移動せず同じ位置にとどまっていると判断した場合など、必要に応じてCore Locationが位置情報の更新を一時停止し、位置情報ハードウェアへの電力供給を止める。
確定した位置情報を取得できない場合にも一時停止。

- activityType

位置情報マネージャはこの値をもとに、位置情報の更新を停止しても問題ないかどうか判断
[取りうる値](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/#//apple_ref/swift/enum/c:@E@CLActivityType)は
CLActivityTypeOther
CLActivityTypeAutomotiveNavigation
CLActivityTypeFitness
CLActivityTypeOtherNavigation

> ユーザあるいはシステムがアプリケーションを停止した場合、新たに位置更新情報が届いても、システムがこれを自動的に再起動することはありません。ユーザが明示的に再起動しない限り、位置更新情報が配送されることはないのです。自動的に再起動されるようにしたければ、領域観測または大幅変更位置情報サービスを利用してください。

```swift:ViewController.swift
        myLocationManager.distanceFilter = 100
        myLocationManager.pausesLocationUpdatesAutomatically = true
        myLocationManager.activityType = CLActivityType.Fitness

//  （中略）

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("error")
    }
    
    func locationManagerDidPauseLocationUpdates(manager: CLLocationManager) {
        print("位置情報更新停止")
    }
    
    func locationManagerDidResumeLocationUpdates(manager: CLLocationManager) {
        print("位置情報更新再開")
    }
```

- allowDeferredLocationUpdatesUntilTraveled:timeout:

位置更新情報配信延期（iOS6以降）
このメソッドは通常、locationManager:didUpdateLocations:メソッドから呼び出す
位置更新情報配信までに移動しなければいけない距離（メートル）と経過時間（秒）を指定、無制限にする場合はCLLocationDistanceMaxやCLTimeIntervalMaxを指定
メソッドを重複して呼び出すことのないよう、デリゲート内部のプロパティを使って、延期しているかどうかを追跡している
アプリケーションで後から問題なく位置情報データを処理できる場合に使用
更新を遅延することでアプリケーションがより長い間スリープ状態を保て、電力の節約になる
位置情報の更新を遅延する機能では、デバイスが位置情報の遅延更新に対応しているかどうかを判別するために、deferredLocationUpdatesAvailableクラスメソッドを必ず呼び出す

```swift:ViewController.swift
    var myLocationManager: CLLocationManager!
    var deferringUpdates = false;

//  （中略）

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if !self.deferringUpdates && CLLocationManager.deferredLocationUpdatesAvailable() {
            myLocationManager.allowDeferredLocationUpdatesUntilTraveled(CLLocationDistanceMax, timeout: CLTimeIntervalMax)
            self.deferringUpdates = true
        }

//  （中略）

    func locationManagerDidResumeLocationUpdates(manager: CLLocationManager) {
        print("位置情報更新再開")
        
        self.deferringUpdates = true
```

## 参考

[位置情報とマッププログラミングガイド](https://developer.apple.com/jp/documentation/LocationAwarenessPG.pdf)
[CLLocationManager Class Reference](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/doc/uid/TP40007125)