Piszę aplikację, która wymaga aktualizacji lokalizacji w tle z dużą dokładnością i niską częstotliwością . Rozwiązaniem wydaje się być działające w tle zadanie NSTimer, które uruchamia aktualizacje menedżera lokalizacji, które następnie natychmiast się wyłączają. 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 w tło
iOS Nie jest to typowy problem z zegarem śledzenia lokalizacji w tle
Długo działający licznik czasu w tle w systemie iOS z trybem tła „lokalizacja”
Pełnoetatowa usługa iOS w tle oparta na śledzeniu lokalizacji
ale jeszcze nie uzyskałem minimalnego działającego przykładu . Po wypróbowaniu każdej permutacji powyższych zaakceptowanych odpowiedzi ustaliłem punkt wyjścia. Wejście w tło:
- (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 metoda delegata:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(@"%@", newLocation);
NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self.locationManager stopUpdatingLocation];
}
Bieżące zachowanie polega na tym, że backgroundTimeRemaining
zmniejsza się od 180 sekund do zera (podczas rejestrowania lokalizacji), a następnie wykonuje procedurę obsługi wygaśnięcia i nie są generowane żadne dalsze aktualizacje lokalizacji. Jak zmodyfikować powyższy kod, aby otrzymywać okresowe aktualizacje lokalizacji w tle przez czas nieokreślony ?
Aktualizacja : Celuję w iOS 7 i wydaje się, że istnieją dowody na to, że zadania w tle zachowują się inaczej:
Odpowiedzi:
Wygląda na
stopUpdatingLocation
to, że to właśnie uruchamia licznik czasu watchdoga w tle, więc zastąpiłem godidUpdateLocation
:[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]; [self.locationManager setDistanceFilter:99999];
co wydaje się skutecznie wyłączać GPS. Selektor tła
NSTimer
zmienia się wtedy w:- (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ł zatrzymany,backgroundTimeRemaining
pozostaje na maksymalnej wartości. To zmniejszone zużycie baterii z ~ 10% na godzinę (ze stałymkCLLocationAccuracyBest
w tle) do ~ 2% na godzinę na moim urządzeniu.źródło
Napisałem aplikację przy użyciu usług lokalizacyjnych, aplikacja musi wysyłać lokalizację co 10 sekund. I 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 aktualizacji lokalizacji.
1. Utwórz LocationManger i rozpocznijUpdatingLocation z dokładnością i filterDistance tak, jak chcesz:
-(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 działała wiecznie przy użyciu metody „allowDeferredLocationUpdatesUntilTraveled: timeout” w tle, musisz ponownie uruchomić aktualizację obiektu updateLocation z nowym parametrem, gdy aplikacja przechodzi w tło, na przykład:
- (void)applicationWillResignActive:(UIApplication *)application { _isBackgroundMode = YES; [_locationManager stopUpdatingLocation]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [_locationManager setDistanceFilter:kCLDistanceFilterNone]; _locationManager.pausesLocationUpdatesAutomatically = NO; _locationManager.activityType = CLActivityTypeAutomotiveNavigation; [_locationManager startUpdatingLocation]; }
3. Aplikacja jest aktualizowana normalnie przez wywołanie zwrotne „locationManager: didUpdateLocations:”:
-(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 następnie wywołaniu zwrotnym „locationManager: didFinishDeferredUpdatesWithError:” w swoim celu
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { _deferringUpdates = NO; //do something }
5. UWAGA: Myślę, że powinniśmy resetować parametry LocationManagera za każdym razem, gdy aplikacja przełącza się między trybem tła / tła.
źródło
allowsBackgroundLocationUpdates = YES
irequestAlwaysAuthorization
lubrequestWhenInUseAuthorization
. Np .: `CLLocationManager * locationManager = [[CLLocationManager przydziel] init]; locationManager.delegate = self; locationManager.allowsBackgroundLocationUpdates = YES; [requestAlwaysAuthorization locationManager]; [locationManager startUpdatingLocation]; `Jeśli masz
UIBackgroundModes
w plistie zlocation
kluczem, nie musisz używaćbeginBackgroundTaskWithExpirationHandler
metody. To jest zbędne. Również używasz go niepoprawnie (patrz tutaj ), ale to dyskusyjne, ponieważ Twój plist jest ustawiony.Po umieszczeniu
UIBackgroundModes location
w pliku plist aplikacja będzie działać w tle przez czas nieokreślony, dopókiCLLocationManger
jest uruchomiona. Jeśli zadzwoniszstopUpdatingLocation
w tle, aplikacja zatrzyma się i nie uruchomi się ponownie.Może mógłbyś zadzwonić
beginBackgroundTaskWithExpirationHandler
tuż przed dzwonieniem,stopUpdatingLocation
a po zakończeniu rozmowystartUpdatingLocation
mógłbyś zadzwonić pod numerendBackgroundTask
aby utrzymać go w tle, gdy GPS jest zatrzymany, ale nigdy tego nie próbowałem - to tylko pomysł.Inną opcją (której nie próbowałem) jest pozostawienie menedżera lokalizacji działającego w tle, ale gdy uzyskasz dokładną lokalizację, zmień
desiredAccuracy
właściwość na 1000 m lub więcej, aby umożliwić wyłączenie chipa GPS (aby oszczędzać baterię). Następnie 10 minut później, gdy potrzebujesz kolejnej aktualizacji lokalizacji, zmieńdesiredAccuracy
tył na 100 m, aby włączyć GPS, aż uzyskasz dokładną lokalizację, powtórz.Kiedy dzwonisz
startUpdatingLocation
do kierownika lokalizacji, musisz dać mu czas na zajęcie stanowiska. Nie powinieneś od razu dzwonićstopUpdatingLocation
. Pozwalamy mu działać przez maksymalnie 10 sekund lub do momentu uzyskania niebuforowanej lokalizacji o wysokiej dokładności.Musisz odfiltrować lokalizacje zapisane w pamięci podręcznej i sprawdzić dokładność uzyskanej lokalizacji, aby upewnić się, że spełnia ona minimalną wymaganą dokładność (patrz tutaj ). Pierwsza otrzymana aktualizacja może mieć 10 minut lub 10 dni. Pierwsza dokładność, jaką uzyskasz, może wynosić 3000 m.
Zamiast tego rozważ użycie interfejsów API zmiany lokalizacji. Gdy otrzymasz powiadomienie o znaczącej zmianie, możesz zacząć
CLLocationManager
na kilka sekund, aby uzyskać pozycję o wysokiej dokładności. Nie jestem pewien, nigdy nie korzystałem z usług znaczącej zmiany lokalizacji.źródło
CoreLocation
wydaje się zalecać użyciebeginBackgroundTaskWithExpirationHandler
podczas przetwarzania danych o lokalizacji w tle: „Jeśli aplikacja na iOS potrzebuje więcej czasu na przetworzenie danych lokalizacji, może zażądać dłuższego czasu wykonania w tle przy użyciu metody beginBackgroundTaskWithName: expirationHandler: klasy UIApplication”. - developer.apple.com/library/ios/documentation/UserExperience/ ...locationManagerDidPauseLocationUpdates
. Sprawdziłem to zachowanie 10 razy!Kiedy nadchodzi czas na uruchomienie usługi lokalizacyjnej i zatrzymanie zadania w tle, zadanie w tle należy zatrzymać z opóźnieniem (powinna wystarczyć 1 sekunda). W przeciwnym razie usługa lokalizacji nie zostanie uruchomiona. Również usługa lokalizacji powinna być włączona przez kilka sekund (np. 3 sekundy).
Istnieje cocoapod APScheduledLocationManager, który umożliwia uzyskiwanie aktualizacji lokalizacji w tle co n sekund z wymaganą dokładnością lokalizacji.
let manager = APScheduledLocationManager(delegate: self) manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
Repozytorium zawiera również przykładową aplikację napisaną w języku Swift 3.
źródło
Co powiesz na wypróbowanie go 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 innychlocationManager
API.Wiele więcej informacji na temat tego interfejsu API zostało już omówione pod tym linkiem
źródło
This interface delivers new events only when it detects changes to the device’s associated cell towers
Musisz dodać tryb aktualizacji lokalizacji w swojej aplikacji, dodając następujący klucz w swoim info.plist.
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
didUpdateToLocation
zostanie wywołana metoda (nawet gdy aplikacja działa w tle). Możesz wykonać dowolną rzecz na podstawie tego wywołania metodyźródło
Po iOS 8 wprowadzono kilka zmian w pobieraniu w tle środowiska CoreLocation i aktualizacjach wprowadzonych przez firmę Apple.
1) Apple wprowadza żądanie AlwaysAuthorization w celu pobrania aktualizacji lokalizacji w aplikacji.
2) Apple wprowadza backgroundLocationupdates do pobierania lokalizacji z tła w 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 } }
źródło
Aby korzystać ze standardowych usług lokalizacyjnych, gdy aplikacja działa w tle, należy najpierw włączyć Tryby w tle na karcie Możliwości w ustawieniach celu i wybrać Aktualizacje lokalizacji.
Lub dodaj go bezpośrednio do Info.plist .
<key>NSLocationAlwaysUsageDescription</key> <string>I want to get your location Information in background</string> <key>UIBackgroundModes</key> <array><string>location</string> </array>
Następnie musisz skonfigurować CLLocationManager
Cel 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];
Szybki
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
źródło
locationManager.allowsBackgroundLocationUpdates = true
źródło