はじめに
アプリで位置情報を取得する際に気になること(バックグラウンドでの取得や充電の消費など)について調査した。
検証用アプリ作成でバックグラウンドで取得して、FirebaseFirestore(DB)に保存、後に取得とかをやってみたのでまとめます。
バックグラウンドでの取得
バックグラウンドで必要な実装は大きく分けて3つ。
OSの位置情報取得ダイアログを出す。
現在地の取得処理。
取得した現在地を保存、今回の場合はFirebaseのDBに保存。
位置情報の取得タイミング
意図的に取得をストップさせる、もしくはアプリのタスクをキルした場合は取得がされない。
それ以外は、フォアグラウンド、バックグラウンド共に動作することを確認。
デバイスがスリープ状態でも位置情報をDBに送信していたことからスリープ時でも取得可能である。
位置情報の取得に関する設定
位置情報の取得は
- 取得距離間隔
- 取得時間間隔(Timerなどで)
- 取得アクティブタイプ(歩きの場合だけ、動いていない時は送信しないなど)
などの設定ができる。(ただし、必ずしもその間隔で動くとは限らない。)
※設定できるプロパティ全て確認したわけではないので他に利用可能なものがあるかもしれない。
消費電力
位置情報精度をkCLLocationAccuracyBestForNavigationとkCLLocationAccuracyBestでそれぞれ設定して確認した。
取得間隔は毎秒。
使用端末はiPhone11, iOS13。
kCLLocationAccuracyBestForNavigationは約30分で5%。
kCLLocationAccuracyBestは約30分で2%。
実装方法
前提環境
- Googleアカウントを作成する
- Firebaseでプロジェクトを作成する。
https://firebase.google.com/docs/firestore/quickstart?authuser=2#swift
公式サイトに載ってますが簡単な流れを一応。
FirebaseFirestoreをインストールする
Podファイルに
pod 'Firebase/Firestore'
記述して
$ pod install
実行。
Cloud Firestore を初期化する
AppdelegateのdidFinishLaunchingWithOptions内で
FirebaseApp.configure() let db = Firestore.firestore()
初期化。
位置情報取得実装
1. iOSの位置情報取得ダイアログを出す。
まず、CLLocationManagerを初期化して設定をする。
private var locationManager: CLLocationManager!
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 5
locationManager.allowsBackgroundLocationUpdates = true
上記のallowsBackgroundLocationUpdatesをtrueにすることでバックグラウンドでの取得を可能にする。
次に、位置情報取得ダイアログの取得処理を追加する。
locationManager.requestWhenInUseAuthorization()
これで位置情報取得許可のダイアログが表示され、許可をすれば位置情報の取得が可能になる。
2. 現在地の取得
まず、許可されているかを確認し、位置情報の取得を開始する。
let status = CLLocationManager.authorizationStatus()
if status == .authorizedWhenInUse || status == .authorizedAlways {
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
次に、CLLocationManagerDelegateを実装する。
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {}
が位置情報が変更されるたびに呼ばれるのでこの中で現在地を取得。
3. 取得した現在地を保存、Firestoreに保存
didUpdateLocations()のlocationsから最新の緯度経度を取得する。
let location = locations.last
let latitude = location?.coordinate.latitude
let longitude = location?.coordinate.longitude
addDocument()でFirestoreに登録する。
詳しい実装については公式ドキュメントを参照。
let myLocation = firestore.db.collection("locations")
let name = UIDevice.current.name
let data: [String: Any] = [
"name":name,
"createAt":FieldValue.serverTimestamp(),
"latitude":self.latitude,
"longitude":self.longitude]
myLocation.addDocument(data: data) { (err) in
¥if let error = err {
print("error:\(error)")
} else {
print("saved!")
}
}