web-dev-qa-db-ja.com

定期的なiOSバックグラウンドロケーション更新

私は、高精度かつ低頻度でバックグラウンドの位置更新を必要とするアプリケーションを書いています。ソリューションは、ロケーションマネージャの更新を開始し、その後すぐにシャットダウンするバックグラウンドNSTimerタスクのようです。この質問は以前に尋ねられました:

iOSアプリケーションでn分ごとにバックグラウンドで位置情報を更新するにはどうすればよいですか?

アプリがバックグラウンドになってからn分ごとにユーザーの位置を取得する

iOSは一般的なバックグラウンドロケーショントラッキングタイマーの問題ではありません

「ロケーション」バックグラウンドモードでのiOS長時間実行バックグラウンドタイマー

位置追跡に基づくiOSフルタイムバックグラウンドサービス

しかし、私はまだ最小の例が動作していません上記の受け入れられた答えのすべての順列を試した後、出発点をまとめました。背景に入る:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"ending background task");
        [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
        self.bgTask = UIBackgroundTaskInvalid;
    }];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
}

そしてデリゲートメソッド:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation {

    NSLog(@"%@", newLocation);

    NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
    [self.locationManager stopUpdatingLocation];

}

現在の動作では、backgroundTimeRemainingが180秒からゼロに減少し(ロケーションのロギング中)、その後、期限切れハンドラーが実行され、それ以上ロケーションの更新は生成されません。 バックグラウンドで定期的にロケーションの更新を無期限に受信するために上記のコードを変更するにはどうすればよいですか

Update:iOS 7をターゲットにしていますが、バックグラウンドタスクの動作が異なることを示すいくつかの証拠があるようです:

バックグラウンドタスクからiOS 7でロケーションマネージャーを起動

90
pcoving

stopUpdatingLocationがバックグラウンドウォッチドッグタイマーをトリガーするようですので、didUpdateLocationを次のように置き換えました:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[self.locationManager setDistanceFilter:99999];

これにより、GPSの電源が効果的にオフになります。バックグラウンドNSTimerのセレクターは次のようになります。

- (void) changeAccuracy {
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}

定期的に精度を切り替えて、数分ごとに高精度の座標を取得します。locationManagerが停止していないため、backgroundTimeRemainingは最大値のままです。これにより、バッテリー消費量が1時間あたり約10%(バックグラウンドでkCLLocationAccuracyBestが一定)から、デバイスで1時間あたり約2%に削減されました。

61
pcoving

ロケーションサービスを使用してアプリを作成しました。アプリは10秒ごとに場所を送信する必要があります。そして、それは非常にうまくいきました。

Appleのドキュメントに従って、「 allowDeferredLocationUpdatesUntilTraveled:timeout 」メソッドを使用するだけです。

手順は次のとおりです。

必須:ロケーションの更新のためにバックグラウンドモードを登録します。

1。LocationMangerとstartUpdatingLocationを作成し、必要に応じて精度とfiltersDistanceを設定します。

-(void) initLocationManager    
{
    // Create the manager object
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
    _locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    _locationManager.desiredAccuracy = 45;
    _locationManager.distanceFilter = 100;
    // Once configured, the location manager must be "started".
    [_locationManager startUpdatingLocation];
}

2。バックグラウンドで「allowDeferredLocationUpdatesUntilTraveled:timeout」メソッドを使用してアプリを永久に実行し続けるには、このようにアプリがバックグラウンドに移動したときにupdateLocationを新しいパラメーターで再起動する必要があります:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];
 }

3。アプリは、「locationManager:didUpdateLocations:」コールバックを使用して、通常どおりupdatedLocationsを取得します。

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//  store data
    CLLocation *newLocation = [locations lastObject];
    self.userLocation = newLocation;

   //tell the centralManager that you want to deferred this updatedLocation
    if (_isBackgroundMode && !_deferringUpdates)
    {
        _deferringUpdates = YES;
        [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];
    }
}

4。ただし、目的に合わせて「locationManager:didFinishDeferredUpdatesWithError:」コールバックでデータを処理する必要があります

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 
}

5。注:アプリがバックグラウンド/フォアグラウンドモードを切り替えるたびに、LocationManagerのパラメーターをリセットする必要があると思います。

45
samthui7
  1. PlistにUIBackgroundModesキーを持つlocationがある場合、beginBackgroundTaskWithExpirationHandlerメソッドを使用する必要はありません。それは冗長です。また、それを誤って使用しています( here を参照)が、plistが設定されているため、それは意味がありません。

  2. PlistにUIBackgroundModes locationを指定すると、CLLocationMangerが実行されている限り、アプリはバックグラウンドで無期限に実行され続けます。バックグラウンドでstopUpdatingLocationを呼び出すと、アプリは停止し、再起動しません。

    beginBackgroundTaskWithExpirationHandlerを呼び出す直前にstopUpdatingLocationを呼び出し、startUpdatingLocationを呼び出した後、endBackgroundTaskを呼び出して、GPSが停止している間バックグラウンドを維持することができますが、それを試した-それは単なるアイデアです。

    別のオプション(私は試していません)は、バックグラウンドでロケーションマネージャーを実行し続けることですが、正確なロケーションを取得したら、desiredAccuracyプロパティを1000m以上に変更してGPSチップをオフにできます(バッテリーを節約するため)。その後、10分後に別の位置の更新が必要になったら、desiredAccuracyを100mに戻し、正確な位置が得られるまでGPSをオンにして、繰り返します。

  3. ロケーションマネージャでstartUpdatingLocationを呼び出すとき、位置を取得する時間を与える必要があります。すぐにstopUpdatingLocationを呼び出さないでください。最大10秒間、またはキャッシュされていない高精度の位置が取得されるまで実行します。

  4. キャッシュされた場所を除外し、取得した場所の精度をチェックして、必要な最小精度を満たしていることを確認する必要があります( here を参照)。最初に取得する更新は、10分または10日前です。最初に得られる精度は3000mです。

  5. 代わりに重要な場所変更APIの使用を検討してください。重要な変更通知を受け取ったら、CLLocationManagerを数秒間起動して、高精度の位置を取得できます。確かなことではないが、重要なロケーション変更サービスを使用したことがない。

36
progrmr

位置情報サービスを開始し、バックグラウンドタスクを停止する時間になったら、バックグラウンドタスクを遅らせて停止する必要があります(1秒で十分です)。そうでない場合、位置情報サービスは開始されません。また、位置情報サービスは数秒間(3秒など)オンにしておく必要があります。

Cocoapod APScheduledLocationManager があります。これにより、目的の位置精度でn秒ごとにバックグラウンドの位置更新を取得できます。

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

リポジトリには、Swift 3で記述されたサンプルアプリも含まれています。

9
sash

startMonitoringSignificantLocationChanges: AP​​Iで試してみませんか?確実に少ない頻度で発火し、精度はかなり良いです。さらに、他のlocationManager AP​​Iを使用するよりも多くの利点があります。

このAPIに関する詳細は、これについて既に説明しました link

1
thatzprem

Info.plistに次のキーを追加して、アプリケーションに位置更新モードを追加する必要があります。

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

didUpdateToLocationメソッドが呼び出されます(アプリがバックグラウンドにある場合でも)。このメソッド呼び出しのベースで何でも実行できます

1
aahsanali

IOS 8以降、CoreLocationフレームワークに関連するバックグラウンドフェッチとAppleによる更新がいくつか変更されています。

1)Appleは、アプリケーションでロケーションの更新を取得するためのAlwaysAuthorizationリクエストを導入します。

2)Appleは、iOSの背景から場所を取得するためのbackgroundLocationupdatesを導入します。

バックグラウンドで場所を取得するには、Xcodeの機能で場所の更新を有効にする必要があります。

//
//  ViewController.Swift
//  DemoStackLocation
//
//  Created by iOS Test User on 02/01/18.
//  Copyright © 2018 iOS Test User. All rights reserved.
//

import UIKit
import CoreLocation

class ViewController: UIViewController {

    var locationManager: CLLocationManager = CLLocationManager()
    override func viewDidLoad() {
        super.viewDidLoad()
        startLocationManager()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    internal func startLocationManager(){
        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.startUpdatingLocation()
    }

}

extension ViewController : CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
        let location = locations[0] as CLLocation
        print(location.coordinate.latitude) // prints user's latitude
        print(location.coordinate.longitude) //will print user's longitude
        print(location.speed) //will print user's speed
    }

}
0
Tech

アプリケーションがバックグラウンドにあるときに標準の位置情報サービスを使用するには、最初に[ターゲット]設定の[機能]タブで[バックグラウンドモード]をオンにし、[位置情報の更新]を選択する必要があります。

または、Info.plistに直接追加します。

<key>NSLocationAlwaysUsageDescription</key>
 <string>I want to get your location Information in background</string>
<key>UIBackgroundModes</key>
 <array><string>location</string> </array>

次に、CLLocationManagerをセットアップする必要があります

目的C

//The Location Manager must have a strong reference to it.
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
//Request Always authorization (iOS8+)
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [_locationManager requestAlwaysAuthorization];
}
//Allow location updates in the background (iOS9+)
if ([_locationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) { _locationManager.allowsBackgroundLocationUpdates = YES;
}
[_locationManager startUpdatingLocation];

Swift

self.locationManager.delegate = self
if #available (iOS 8.0,*) {
    self.locationManager.requestAlwaysAuthorization()
}
if #available (iOS 9.0,*) {
    self.locationManager.allowsBackgroundLocationUpdates = true
}
self.locationManager.startUpdatingLocation()

参照: https://medium.com/@javedmultani16/location-service-in-the-background-ios-942c89cd99ba

0