Okresowe aktualizacje lokalizacji tła systemu iOS

Piszę aplikację, która wymaga aktualizacji lokalizacji w tle z wysoką dokładnością i niską częstotliwością . Rozwiązaniem wydaje się być zadanie tła NSTimer, które uruchamia aktualizacje menedżera lokalizacji, który następnie natychmiast się wyłącza. To pytanie zostało już zadane:

Jak uzyskać aktualizację lokalizacji w tle co n minut w mojej aplikacji na iOS?

Uzyskiwanie lokalizacji użytkownika co n minut po przejściu aplikacji do tło

IOS nie jest typowym problemem czasomierza śledzenia lokalizacji w tle

IOS long-running background timer with" location " background mode

IOS w pełnym wymiarze czasu pracy w tle-usługa oparta na śledzeniu lokalizacji

Ale nie mam jeszczeminimalnego przykładu działającego. Po wypróbowaniu każdej permutacji powyższych zaakceptowanych odpowiedzi, ułożyłem punkt wyjścia. Wpisywanie tła:

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

I delegat "metoda": {]}

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

    NSLog(@"%@", newLocation);

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

}

Obecne zachowanie jest takie, że backgroundTimeRemaining zmniejsza się z 180 sekund do zera (podczas logowania lokalizacji), a następnie program obsługi wygaśnięcia jest wykonywany i nie są generowane dalsze aktualizacje lokalizacji. Jak zmodyfikować powyższy kod, aby otrzymywać okresowe aktualizacje lokalizacji w tle na czas nieokreślony?

Aktualizacja: celuję w iOS 7 i wydaje się, że istnieją pewne dowody na to, że zadania w tle zachowują się inaczej: {]}

Miejsce Startu Menedżer w iOS 7 z zadania w tle

Author: Honey, 2013-09-27

8 answers

Wygląda na to, że stopUpdatingLocation jest tym, co uruchamia zegar w tle, więc zamieniłem go na didUpdateLocation na:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[self.locationManager setDistanceFilter:99999];
Co wydaje się skutecznie wyłączać GPS. Selektor tła NSTimer staje się wtedy:
- (void) changeAccuracy {
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}

Wszystko, co robię, to okresowe przełączanie dokładności, aby uzyskać współrzędną o wysokiej dokładności co kilka minut, a ponieważ locationManager nie została zatrzymana, backgroundTimeRemaining pozostaje na maksymalnej wartości. Zmniejszenie zużycia baterii od ~10% na godzinę (przy stałym kCLLocationAccuracyBest w tle) do ~2% na godzinę na moim urządzeniu.

 61
Author: pcoving,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-29 17:16:27

Napisałem aplikację za pomocą usług lokalizacji, aplikacja musi wysyłać lokalizację co 10s. I to działało bardzo dobrze.

Po prostu użyj metody "allowDeferredLocationUpdatesUntiltraveled:timeout ", zgodnie z dokumentem Apple.

Kroki są następujące:

Wymagane: Zarejestruj tryb tła dla lokalizacji aktualizacji.

1. twórz LocationManger i startUpdatingLocation, z dokładnością i odpornością filtrowaną jak cokolwiek chcesz want:

-(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. aby aplikacja była zawsze uruchamiana przy użyciu metody" allowDeferredLocationUpdatesUntiltraveled:timeout " w tle, musisz ponownie uruchomić updatingLocation z nowym parametrem, gdy aplikacja przeniesie się do tła, tak:

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

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

3. App gets updatedLocations as normal with "locationManager: didUpdateLocations:" 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. ale powinieneś obsłużyć dane w "locationManager:didFinishDeferredUpdatesWithError:" callback for twój cel

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

     _deferringUpdates = NO;

     //do something 
}

5. Uwaga: myślę, że powinniśmy zresetować parametry LocationManager za każdym razem, gdy aplikacja przełącza się między trybem background/forground.

 44
Author: samthui7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 07:05:06
  1. Jeśli masz UIBackgroundModes w pliście z kluczem location, nie musisz używać metody beginBackgroundTaskWithExpirationHandler. To zbędne. Również używasz go nieprawidłowo (zobacz tutaj ), ale to jest dyskusyjne, ponieważ twój plist jest ustawiony.

  2. Z UIBackgroundModes location w pliście aplikacja będzie działać w tle w nieskończoność tylko tak długo, jak działa CLLocationManger. Jeśli wywołasz stopUpdatingLocation w tle, aplikacja zatrzyma się i nie uruchomi ponownie.

    Może mógłbyś zadzwonić beginBackgroundTaskWithExpirationHandler tuż przed wywołaniem stopUpdatingLocation, a następnie po wywołaniu startUpdatingLocation możesz zadzwonić do endBackgroundTask, aby zatrzymać go podczas zatrzymania GPS, ale nigdy tego nie próbowałem - to tylko pomysł.

    Inną opcją (której nie próbowałem) jest utrzymywanie menedżera lokalizacji działającego w tle, ale po uzyskaniu dokładnej lokalizacji zmień właściwość desiredAccuracy na 1000M lub wyższą, aby umożliwić wyłączenie układu GPS (aby zaoszczędzić baterię). Następnie 10 minut później, gdy potrzebujesz innej lokalizacji update, Zmień desiredAccuracy z powrotem na 100m, aby włączyć GPS, dopóki nie uzyskasz dokładnej lokalizacji, powtórz.

  3. Kiedy dzwonisz startUpdatingLocation do menedżera lokalizacji, musisz dać mu czas na zdobycie stanowiska. Nie należy natychmiast dzwonić stopUpdatingLocation. Pozwalamy mu działać maksymalnie przez 10 sekund lub do czasu uzyskania Nie buforowanej lokalizacji o wysokiej dokładności.

  4. Musisz odfiltrować buforowane lokalizacje i sprawdzić dokładność lokalizacji, aby upewnić się, że spełnia Twoje minimum wymagana dokładność (patrz tutaj ). Pierwsza aktualizacja może mieć 10 minut lub 10 dni. Pierwsza dokładność jaką uzyskasz może wynosić 3000m.

  5. Zamiast tego rozważ użycie interfejsów API znaczącej zmiany lokalizacji. Po otrzymaniu powiadomienia o istotnych zmianach możesz uruchomić CLLocationManager na kilka sekund, aby uzyskać wysoką dokładność pozycji. Nie jestem pewien, nigdy nie korzystałem z usług zmiany lokalizacji.

 32
Author: progrmr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:33

Gdy nadszedł czas, aby uruchomić usługę lokalizacji i zatrzymać zadanie w tle, zadanie w tle powinno zostać zatrzymane z opóźnieniem (1 sekunda powinna wystarczyć). W przeciwnym razie usługa lokalizacji nie rozpocznie się. Również usługa lokalizacji powinna być włączona na kilka sekund (np. 3 sekundy).

Istnieje CocoapodAPScheduledLocationManager , który pozwala na pobieranie aktualizacji lokalizacji w tle coN sekund z żądaną dokładnością lokalizacji.

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

Repozytorium zawiera również przykładowa aplikacja napisana w języku Swift 3.

 8
Author: sash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 14:37:41

Może spróbujesz z startMonitoringSignificantLocationChanges: API? Zdecydowanie strzela z mniejszą częstotliwością, a celność jest dość dobra. Dodatkowo ma o wiele więcej zalet niż używanie innych API locationManager.

Dużo więcej o tym API zostało już omówione na tym linku

 1
Author: thatzprem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:40

Musisz dodać tryb aktualizacji lokalizacji w aplikacji, dodając następujący klucz w informacji.plist.

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

didUpdateToLocation metoda zostanie wywołana (nawet gdy aplikacja jest w tle). Możesz wykonać dowolną rzecz na podstawie wywołania tej metody

 1
Author: aahsanali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-27 05:28:01

Ten projekt będzie działał do zarządzania lokalizacją w tle.

LOCATION BACKGROUND UPDATER

Będzie zarządzać automatycznie, jeśli aplikacja wejdzie w tło i trzeba wysłać połączenie sieciowe, aby zaktualizować lokalizację.

 0
Author: Esha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 18:34:47

Po iOS 8 ich jest kilka zmian w corelocation framework związane pobieranie tła i aktualizacje wykonane przez apple.

1) Apple wprowadza zawsze prośbę autoryzacji o pobranie aktualizacji lokalizacji w aplikacji.

2) Apple wprowadza backgroundLocationupdates do pobierania lokalizacji z tła w systemie iOS.

Aby pobrać lokalizację w tle, musisz włączyć aktualizację lokalizacji w możliwościach 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
Author: Tech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-02 12:28:08