wake-up-neo.com

Regelmäßige Aktualisierungen des iOS-Hintergrunds

Ich schreibe eine Anwendung, die Hintergrundstandortaktualisierungen mit hoher Genauigkeit und niedriger Frequenz erfordert. Die Lösung scheint eine NSTimer-Hintergrundaufgabe zu sein, die die Aktualisierungen des Standortmanagers startet und dann sofort herunterfährt. Diese Frage wurde zuvor gestellt:

Wie bekomme ich in meiner iOS-Anwendung alle n Minuten ein Update zum Hintergrundstandort?

Benutzerplatz alle n Minuten abrufen, nachdem die App in den Hintergrund gelangt

iOS Nicht das typische Problem mit dem Hintergrundort-Tracking-Timer

Langlebiger iOS-Hintergrund-Timer mit Hintergrundmodus "location"

iOS-Vollzeit-Hintergrundservice basierend auf Standortverfolgung

aber ich muss noch ein minimum-Beispiel zum Laufen bekommen. Nachdem ich jede Umstellung der oben genannten akzeptierten Antworten ausprobiert hatte, legte ich einen Ausgangspunkt fest. Hintergrund eingeben:

- (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];
}

und die Delegatmethode:

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

    NSLog(@"%@", newLocation);

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

}

Das aktuelle Verhalten ist, dass die Variable backgroundTimeRemaining von 180 Sekunden auf null verringert wird (während der Speicherort protokolliert wird). Anschließend wird der Ablaufhandler ausgeführt und es werden keine weiteren Standortaktualisierungen generiert. Wie ändere ich den obigen Code, um periodische Standortaktualisierungen unbegrenzt im Hintergrund zu erhalten?

Update: Ich ziele auf iOS 7 ab und es gibt Anzeichen dafür, dass sich Hintergrundaufgaben anders verhalten:

Starten Sie den Standortmanager in iOS 7 über die Hintergrundaufgabe

87
pcoving

Es scheint, dass stopUpdatingLocation den Hintergrund-Watchdog-Timer auslöst, also habe ich ihn in didUpdateLocation durch Folgendes ersetzt:

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

was scheint das GPS effektiv herunterzufahren. Der Auswahlschalter für den Hintergrund NSTimer wird dann zu:

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

Alles was ich mache ist das periodische Wechseln der Genauigkeit, um alle paar Minuten eine hochgenaue Koordinate zu erhalten, und weil locationManager nicht angehalten wurde, bleibt backgroundTimeRemaining auf dem Maximalwert. Dies reduziert den Batterieverbrauch von ~ 10% pro Stunde (bei konstantem kCLLocationAccuracyBest Hintergrund) auf ~ 2% pro Stunde auf meinem Gerät.

61
pcoving

Ich habe eine App mit Location Services geschrieben, die App muss alle 10s eine Location senden ... und es hat sehr gut funktioniert.

Verwenden Sie einfach die Methode " allowDeferredLocationUpdatesUntilTraveled: timeout " nach dem Dokument von Apple.

Schritte sind wie folgt:

Erforderlich: Hintergrundmodus für Update-Standort registrieren.

1. Create LocationManger und startUpdatingLocation, mit Genauigkeit und gefiltertem Abstand, wie Sie möchten:

-(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. Damit die App für immer mit der Methode "allowDeferredLocationUpdatesUntilTraveled: timeout" im Hintergrund ausgeführt werden kann, müssen Sie updateLocation mit neuen Parametern erneut starten, wenn die App in den Hintergrund wechselt.

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

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

3. Die App wird wie gewohnt mit "locationManager: didUpdateLocations:" Rückruf aktualisiert: callback: 

-(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. Sie sollten jedoch mit den Daten in "locationManager: didFinishDeferredUpdatesWithError:" zu Ihrem Zweck umgehen

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

     _deferringUpdates = NO;

     //do something 
}

5.NOTE: Ich denke, wir sollten die Parameter von LocationManager jedes Mal neu einstellen, wenn die App zwischen Hintergrund- und Forground-Modus wechselt.

44
samthui7
  1. Wenn Sie UIBackgroundModes in Ihrer Liste mit location-Schlüssel haben, müssen Sie die beginBackgroundTaskWithExpirationHandler-Methode nicht verwenden. Das ist überflüssig. Sie verwenden es auch falsch (siehe hier ), aber das ist umstritten, da Ihre Plist gesetzt ist. 

  2. Mit UIBackgroundModes location in der Plist wird die App nur dann unbegrenzt im Hintergrund ausgeführt, solange CLLocationManger ausgeführt wird. Wenn Sie stopUpdatingLocation im Hintergrund aufrufen, wird die App angehalten und startet nicht mehr. 

    Vielleicht könnten Sie beginBackgroundTaskWithExpirationHandler kurz vor dem Aufruf von stopUpdatingLocation anrufen, und nachdem Sie startUpdatingLocation aufgerufen haben, können Sie die endBackgroundTask aufrufen, um sie im Hintergrund zu halten, während das GPS gestoppt ist.

    Eine weitere Option (die ich nicht ausprobiert habe) ist, den Standortmanager im Hintergrund laufen zu lassen. Sobald Sie jedoch einen genauen Standort ermittelt haben, ändern Sie die desiredAccuracy-Eigenschaft auf 1000 m oder höher, damit der GPS-Chip ausgeschaltet werden kann (um Batterie zu sparen). . Wenn Sie nach 10 Minuten eine weitere Standortaktualisierung benötigen, ändern Sie die desiredAccuracy wieder auf 100 m, um das GPS einzuschalten, bis Sie einen genauen Standort erhalten. Wiederholen Sie diesen Vorgang.

  3. Wenn Sie startUpdatingLocation im Standortmanager aufrufen, müssen Sie ihm Zeit geben, um eine Position zu erhalten. Sie sollten stopUpdatingLocation nicht sofort aufrufen. Wir lassen es maximal 10 Sekunden lang laufen, oder bis wir eine nicht zwischengespeicherte hochgenaue Position erhalten.

  4. Sie müssen zwischengespeicherte Positionen herausfiltern und die Genauigkeit der Position überprüfen, die Sie erhalten, um sicherzustellen, dass sie der geforderten Mindestgenauigkeit entspricht (siehe hier ). Das erste Update, das Sie erhalten, kann 10 Minuten oder 10 Tage alt sein. Die erste Genauigkeit, die Sie erhalten, kann 3000 m betragen. 

  5. Verwenden Sie stattdessen die APIs für signifikante Standortänderungen. Sobald Sie die Benachrichtigung über eine bedeutende Änderung erhalten, können Sie CLLocationManager für einige Sekunden starten, um eine Position mit hoher Genauigkeit zu erhalten. Ich bin mir nicht sicher, ich habe die bedeutenden Standortänderungsdienste noch nie genutzt.

32
progrmr

Wenn es Zeit ist, den Ortungsdienst zu starten und die Hintergrundaufgabe zu beenden, sollte die Hintergrundaufgabe mit einer Verzögerung angehalten werden (1 Sekunde sollte ausreichen). Andernfalls startet der Standortdienst nicht. Der Ortungsdienst sollte für einige Sekunden eingeschaltet bleiben (z. B. 3 Sekunden).

Es gibt einen Cocoapod APScheduledLocationManager , mit dem alle n Sekunden Hintergrundaktualisierungen im Hintergrund mit der gewünschten Standortgenauigkeit abgerufen werden können.

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

Das Repository enthält auch eine in Swift 3 geschriebene Beispiel-App.

8
sash

Wie wäre es mit der startMonitoringSignificantLocationChanges:-API? Es feuert definitiv mit weniger Frequenz und die Genauigkeit ist einigermaßen gut. Darüber hinaus bietet es weitaus mehr Vorteile als andere locationManager-APIs.

In Bezug auf diese API wurde bereits viel mehr darüber diskutiert. Link

1
thatzprem

Sie müssen den Standortaktualisierungsmodus in Ihrer Anwendung hinzufügen, indem Sie den folgenden Schlüssel in Ihrer info.plist hinzufügen.

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

Die didUpdateToLocation-Methode wird aufgerufen (auch wenn sich Ihre App im Hintergrund befindet). Sie können alles auf der Grundlage dieses Methodenaufrufs ausführen

1
aahsanali

Nach iOS 8 gibt es mehrere Änderungen in Bezug auf das Abrufen und Aktualisieren des CoreLocation Frameworks, die von Apple vorgenommen wurden.

1) Apple führt die AlwaysAuthorization-Anforderung ein, um die Standortaktualisierung in der Anwendung abzurufen.

2) Apple führt backgroundLocationupdates ein, um den Standort aus dem Hintergrund in iOS abzurufen.

Um den Standort im Hintergrund abzurufen, müssen Sie die Standortaktualisierung in den Funktionen von Xcode aktivieren.

//
//  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

Um Standard-Standortdienste zu verwenden, während sich die Anwendung im Hintergrund befindet, müssen Sie zuerst die Hintergrundmodi auf der Registerkarte Funktionen der Zieleinstellungen aktivieren und Standortaktualisierungen auswählen.

Oder fügen Sie es direkt in die Info.plist ein.

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

Dann müssen Sie den CLLocationManager einrichten

Ziel 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()

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

0