Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

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

Info.plistのRequired device capabilitiesにlocation-servicesとgps追加
Info.plistのInformation Property ListにNSLocationAlwaysUsageDescriptionを追加して、許可を求めるダイアログに表示する文字列を設定
Button * 2(開始・終了用)をストーリーボードに配置し、Outlet・Actionを作成してViewController.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")
    }

詳しくは定期的に位置情報を更新するを参照

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

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

電池消費を抑える設定

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

  • pausesLocationUpdatesAutomatically

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

  • activityType

位置情報マネージャはこの値をもとに、位置情報の更新を停止しても問題ないかどうか判断
取りうる値
CLActivityTypeOther
CLActivityTypeAutomotiveNavigation
CLActivityTypeFitness
CLActivityTypeOtherNavigation

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

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クラスメソッドを必ず呼び出す

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

参考

位置情報とマッププログラミングガイド
CLLocationManager Class Reference

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away