ユーザーの場所を追跡し、場所が更新されるたびにローカル通知を作成するシンプルなアプリを作成しました。
以下のバックグラウンドモードを有効にしました。
let locationManager = CLLocationManager()
open override func viewDidLoad() {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 10
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
}
open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let notification = UILocalNotification()
notification.alertBody = "location updated"
notification.fireDate = Date()
UIApplication.shared.scheduleLocalNotification(notification)
}
NSLocationAlwaysUsageDescription
に文字列を設定し、許可を求めます。ユーザーは、アプリが初めて読み込まれたときに常に使用するためのアクセス許可を付与します。
アプリがフォアグラウンドにあるとき、バックグラウンドになったときまだ機能しているバッテリーまたはその他によって変更可能な少なくとも5〜40分の時間範囲でうまく機能します開いたアプリ。
問題は、それが動作を停止する理由です、動作し続けることが期待されていませんか?
Apple docs。
アプリがバックグラウンドに移行したら、重要な現在地の更新に切り替えます。 iOSは、バックグラウンドで無期限に存続している場合、アプリをアンロードします。
locationManager.pausesLocationUpdatesAutomatically = false
ロケーションマネージャオブジェクトの desiredAccuracy
プロパティを設定します
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
CLLocationAccuracy
定数のいずれかを使用できます
重要
デフォルトでは、iOSデバイスでの標準の場所の更新は、最高の精度レベルで実行されます。アプリの要件に合わせてこれらの設定を変更します。そうしないと、アプリが不必要にエネルギーを無駄にします。
ロケーションマネージャーオブジェクトの pausesLocationUpdatesAutomatically
プロパティをtrue
に設定します
self.locationManager.pausesLocationUpdatesAutomatically = true
重要
使用中の承認があるアプリの場合、位置情報の更新を一時停止すると、アプリが再度起動され、それらの更新を再開できるようになるまで、位置情報の変更へのアクセスが終了します。位置情報の更新を完全に停止したくない場合は、このプロパティを無効にし、アプリがバックグラウンドに移動したときに位置の精度を
kCLLocationAccuracyThreeKilometers
に変更することを検討してください。そうすることで、ロケーションの更新を電力に優しい方法で受信し続けることができます。
ロケーションマネージャーオブジェクトの allowsBackgroundLocationUpdates
プロパティをtrue
に設定します
self.locationManager.allowsBackgroundLocationUpdates = true
一時停止したときに位置情報の更新を受け取りたいアプリは、アプリのInfo.plistファイルにUIBackgroundModesキー(位置値を含む)を含め、このプロパティの値をtrueに設定する必要があります。バックグラウンド更新には、場所の値を持つUIBackgroundModesキーの存在が必要です
activityType
プロパティを設定して、特定の時間にアプリが実行しているロケーションアクティビティのタイプをCore Locationに知らせます
self.locationManager.activityType = .automotiveNavigation
CLActivityType
のいずれかのケースを使用できます
GPSハードウェアを搭載したサポートされているデバイスでは、アプリがバックグラウンドにある場合にロケーションマネージャーにロケーション更新の配信を延期させることができます。たとえば、ハイキングトレイルでユーザーの位置を追跡するフィットネスアプリは、ユーザーが一定の距離を移動するか、一定の時間が経過するまで更新を延期できます。
参照を検索した後(制限について話します)、Apple Core Location Best Practices ビデオセッションが役に立つかもしれません!at 06:53
バックグラウンドでの標準的な場所の話:
さらに、Core Locationはアプリの実行を継続するためのアクションを実行しません。そのため、何らかの理由でバックグラウンドで実行しており、ロケーションセッションを開始することにした場合、更新を受け取る可能性がありますが、受信する前に中断される可能性もあります受け取りたいすべての情報...
実際、私は以前にこの問題に直面しました-回避策として-コアロケーションは、ユーザーのロケーションを追跡してそのロケーションに無関係な機能を実行します-ファイルをアップロードしています-しかし、この回避策はiOS 9以来機能しませんでしたリリースされました;この問題について question を引用して投稿しました。
ただし、次のことを目指している場合、あなたのケースは私が直面したものと同じではないようです:
...場所が更新されるたびにローカル通知を作成します。
次に、User Notification Framework- NLocationNotificationTrigger と統合するアプローチに従う必要があります。
ローカル通知の配信を可能にするためにユーザーが到達する必要がある地理的な場所。
ビデオセッションでも言及されています(08:59
)。
おそらく、これはあなたが探しているものではないかもしれませんが、バックグラウンド実行が継続して実行される保証はないので、あなたは-どういうわけか-あなたのアプリにそれを統合して望ましい機能を達成する方法を見つけるかもしれません。
iOS 11のアップデート:
ロケーションアクセスをリクエストする適切な方法については、 this answer を確認する必要があるかもしれません。
それの音によって、アプリはメモリの制約のために殺されています。ただし、ここで説明するように、新しい場所が利用可能になったら再起動する必要があります。 https://developer.Apple.com/documentation/uikit/uiapplicationlaunchoptionskey/1623101-location
application(_:didFinishLaunchingWithOptions:)
が呼び出され、起動オプションに 'location'キーが存在するはずです。その後、場所を消費しているものは何でも再作成し、記録を続けることができます。
再起動されていない場合は、メモリが不足している可能性があります。アプリのメモリ消費量を確認し、applicationDidReceiveMemoryWarning(_:)
が呼び出されているかどうかを確認します。
バックグラウンドタスクを実装していないと思います。 here と読むことができます。
上記のリンクのセクション「長時間実行タスクの実装」ポイント番号3はあなたの状況です。したがって、プロジェクトでバックグラウンドの場所の更新を使用でき、同じためにバックグラウンドタスクも実装する必要があることは有効です。
ユーザーの位置を追跡するには、3つの方法があります(上記のセクションの「ユーザーの位置の追跡」):-
バックグラウンド位置情報サービス(これを試みていると思います)および解決策は、バックグラウンドタスクを追加することです。
以下はバックグラウンドタスクの例であり、要件に応じて変更できます。過去2時間以来機能し、アプリは引き続きバックグラウンドで場所を更新します。
。 AppDelegateクラスで、以下の関数を更新してから、アプリをバックグラウンドで実行してください。
func applicationDidEnterBackground(_ application: UIApplication) {
application.beginBackgroundTask(withName: "") {}
}
そして、以下は私のViewControllerクラスです
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self;
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.allowsBackgroundLocationUpdates = true
locationManager.distanceFilter = kCLDistanceFilterNone
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
self.locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("didUpdateLocations \(Date())")
self.locationManager.stopUpdatingLocation()
}
}