ユーザーがアプリを使用していなくてもユーザーの位置情報を取得したいのですが、ホームボタンを押してアプリケーションがバックグラウンド状態になった後、位置情報を取得できますが、数秒後に位置情報の更新が停止しました。そして、私がアプリの場所の更新を強制終了しているときは停止しました。これはアプリデリゲートの私のコードです。
let locationManager = CLLocationManager()
var LatitudeGPS = String()
var LongitudeGPS = String()
var speedGPS = String()
var Course = String()
var Altitude = String()
var bgtimer = Timer()
func applicationDidEnterBackground(_ application: UIApplication) {
self.doBackgroundTask()
}
func beginBackgroundUpdateTask() {
backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
}
func doBackgroundTask() {
DispatchQueue.global(qos: .background).async {
self.beginBackgroundUpdateTask()
self.StartupdateLocation()
self.bgtimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.bgtimer(timer:)), userInfo: nil, repeats: true)
RunLoop.current.add(self.bgtimer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
self.endBackgroundUpdateTask()
}
}
func bgtimer(timer:Timer!){
print("Fired from Background ************************************")
updateLocation()
}
func StartupdateLocation() {
locationManager.delegate = self
locationManager.startUpdatingLocation()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
}
func updateLocation() {
locationManager.startUpdatingLocation()
locationManager.stopUpdatingLocation()
print("Latitude: \(LatitudeGPS)")
print("Longitude: \(LongitudeGPS)")
print("Speed: \(speedGPS)")
print("Heading: \(Course)")
print("Altitude BG: \(Altitude)")
DispatchQueue.main.async {
print(UIApplication.shared.backgroundTimeRemaining)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
LatitudeGPS = String(format: "%.10f", manager.location!.coordinate.latitude)
LongitudeGPS = String(format: "%.10f", manager.location!.coordinate.longitude)
speedGPS = String(format: "%.3f", manager.location!.speed)
Altitude = String(format: "%.3f", manager.location!.altitude)
Course = String(format: "%.3f", manager.location!.course)
}
}
数秒後にアプリケーションが終了し、場所の更新が停止したと思います。 20分後にアプリケーションが終了した(OSまたはユーザー)場所の更新を停止して、バッテリーの充電を維持したいと思います。場所の更新での私の問題はどこにありますか。
変更することがいくつかあります。
ステップ1:
以下に示すように、プロジェクトの機能セクションでロケーション更新バックグラウンドモードが有効になっていることを確認してください
ステップ2:
そして、私がアプリの場所の更新を強制終了しているときは停止しました。
Apple docsからの引用
このサービスを開始し、その後アプリが終了した場合、新しいイベントが到着すると、システムはアプリをバックグラウンドで自動的に再起動します。このような場合、アプリデリゲートのapplication(:willFinishLaunchingWithOptions :)メソッドとapplication(:didFinishLaunchingWithOptions :)メソッドに渡されるオプションディクショナリには、アプリを示すためのキーの場所が含まれますロケーションイベントのために発売されました。再起動時に、ロケーションマネージャオブジェクトを設定し、このメソッドを呼び出してロケーションイベントの受信を継続する必要があります。位置情報サービスを再開すると、現在のイベントがすぐに代理人に配信されます。さらに、ロケーションマネージャオブジェクトのロケーションプロパティには、ロケーションサービスを開始する前でも、最新のロケーションオブジェクトが入力されます。
上記のステートメントで注意すべき重要なことは
再起動時に、ロケーションマネージャオブジェクトを設定し、このメソッドを呼び出して、ロケーションイベントの受信を継続する必要があります。
つまり、現在のロケーションマネージャはあまり役に立たないため、新しいロケーションマネージャを作成し、新しいインスタンスを設定して、もう一度startMonitorSignificantLocationChanges
を呼び出す必要があります。
そのため、iOSは、startMonitoringSignificantLocationChanges
を使用した場合にのみ、終了したアプリに位置情報の更新を送信します。
これらはすべて、アプリが終了し、iOSが位置情報の更新を受信したときにアプリを再起動した場合にのみ適用されます。ただし、アプリが単にバックグラウンドにある場合は、startMonitorSignificantLocationChanges
の使用について何もする必要はありません。
一方、startUpdatingLocation
は、アプリがバックグラウンド/フォアグラウンドモードの場合にのみ機能します。アプリが一時停止または強制終了されると、iOSは場所の更新を停止します。
このサービスを開始してアプリが一時停止された場合、システムはアプリの実行が再開されるまで(フォアグラウンドまたはバックグラウンドで)イベントの配信を停止します。アプリが終了すると、新しいロケーションイベントの配信は完全に停止します。したがって、アプリがバックグラウンドでロケーションイベントを受信する必要がある場合は、Info.plistファイルにUIBackgroundModesキー(ロケーション値を含む)を含める必要があります。
したがって、コードを変更します
locationManager.startMonitoringSignificantLocationChange()
さて、それはstartMonitoringSignificantLocationChanges
とstartupdatinglocation
の適切な使用法についてでした。これで、コードの間違いをタイマーで確認できます。
間違い1:
self.bgtimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.bgtimer(timer:)), userInfo: nil, repeats: true)
タイマーを使用して、場所に関するタイムリーな更新を取得します。それはそれがどのように機能するかではありません!!!タイマーを永久に実行することはできません。アプリが一時停止または終了するとすぐにタイマーが停止します。 Location Managerは、場所が変更されたときにアプリに通知するため、それだけに頼る必要があります。タイマーを実行して、場所の更新をタイムリーに確認することはできません。一時停止または終了した状態では実行されません。
間違い2:
func updateLocation() {
locationManager.startUpdatingLocation()
locationManager.stopUpdatingLocation()
後続のステートメントで更新場所を開始および停止するのはなぜですか?それはあまり意味がありません。
間違い3:
func StartupdateLocation() {
locationManager.delegate = self
locationManager.startUpdatingLocation()
StartupdateLocation
は複数回呼び出され、このメソッドを呼び出すたびに、ロケーションマネージャーの同じインスタンスでstartUpdatingLocation
を繰り返し呼び出します。あなたはそれをする必要はありません! startUpdatingLocation
またはstartMonitoringSignificantLocationChange
は1回だけ呼び出すことができます。