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

Szukam sposobu, aby uzyskać aktualizację lokalizacji w tle co n minut w mojej aplikacji na iOS. Używam iOS 4.3 i rozwiązanie powinno działać na nie jailbroken iPhone.

Próbowałem / rozważałem następujące opcje:

  • CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges: działa to w tle zgodnie z oczekiwaniami, w oparciu o skonfigurowane właściwości, ale wydaje się, że nie można wymusić aktualizacji lokalizacji co n minut
  • NSTimer: działa, gdy aplikacja jest uruchomiona na pierwszym planie, ale nie wydaje się być zaprojektowany do zadań w tle
  • powiadomienia lokalne: powiadomienia lokalne mogą być zaplanowane co n minut, ale nie jest możliwe wykonanie kodu, aby uzyskać bieżącą lokalizację (bez konieczności uruchamiania aplikacji przez powiadomienie). To podejście również nie wydaje się być czyste podejście, ponieważ nie jest to, co powiadomienia powinny być używane do.
  • UIApplication:beginBackgroundTaskWithExpirationHandler: z tego co rozumiem, to powinno być użyte do zakończenia jakiejś pracy w tle (także ograniczonej czasowo) gdy aplikacja jest przenoszona do tła, a nie implementuje "długotrwałe" procesy w tle.

Jak mogę zaimplementować te regularne aktualizacje lokalizacji w tle?

Author: Ashwini, 2011-06-14

15 answers

Znalazłem rozwiązanie, aby zaimplementować to za pomocą forów programistów Apple:

  • Określ location background mode
  • Utwórz NSTimer w tle za pomocą UIApplication:beginBackgroundTaskWithExpirationHandler:
  • Gdy n jest mniejsze niż UIApplication:backgroundTimeRemaining będzie działać dobrze. Gdy njest większe, location manager powinno być włączone (i wyłączone) ponownie, zanim nie zostanie pozostały czas, aby uniknąć zabicia zadania w tle.

Działa to, ponieważ lokalizacja jest jedną z trzech dozwolone typy wykonania w tle .

Uwaga: straciłem trochę czasu testując to w symulatorze, gdzie nie działa. Jednak działa dobrze na moim telefonie.

 109
Author: wjans,
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-06 13:53:44

On iOS 8/9/10 aby dokonać aktualizacji lokalizacji w tle co 5 minut, wykonaj następujące czynności:

  1. Przejdź do projektu -> możliwości -> tryby tła -> Wybierz aktualizacje lokalizacji

  2. Przejdź do projektu -> Info - > Dodaj klucz NSLocationAlwaysUsageDescription z pustą wartością (lub opcjonalnie dowolny tekst)

  3. Aby lokalizacja działała, gdy aplikacja jest w tle i wysyłać współrzędne do serwisu internetowego lub robić z nimi cokolwiek co 5 minut, zaimplementuj ją jak w poniższym kodzie.

Nie używam żadnych zadań w tle ani timerów. Przetestowałem ten kod na moim urządzeniu z systemem iOS 8.1, który leżał na moim biurku przez kilka godzin z moją aplikacją działającą w tle. Urządzenie było zablokowane, a kod działał prawidłowo przez cały czas.

@interface LocationManager () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSDate *lastTimestamp;

@end

@implementation LocationManager

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
        LocationManager *instance = sharedInstance;
        instance.locationManager = [CLLocationManager new];
        instance.locationManager.delegate = instance;
        instance.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // you can use kCLLocationAccuracyHundredMeters to get better battery life
        instance.locationManager.pausesLocationUpdatesAutomatically = NO; // this is important
    });

    return sharedInstance;
}

- (void)startUpdatingLocation
{
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];

    if (status == kCLAuthorizationStatusDenied)
    {
        NSLog(@"Location services are disabled in settings.");
    }
    else
    {
        // for iOS 8
        if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
        {
            [self.locationManager requestAlwaysAuthorization];
        }
        // for iOS 9
        if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        {
            [self.locationManager setAllowsBackgroundLocationUpdates:YES];
        }

        [self.locationManager startUpdatingLocation];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *mostRecentLocation = locations.lastObject;
    NSLog(@"Current location: %@ %@", @(mostRecentLocation.coordinate.latitude), @(mostRecentLocation.coordinate.longitude));

    NSDate *now = [NSDate date];
    NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0;

    if (!self.lastTimestamp || interval >= 5 * 60)
    {
        self.lastTimestamp = now;
        NSLog(@"Sending current location to web service.");
    }
}

@end
 52
Author: Leszek Szary,
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-06-25 18:42:24

Zrobiłem to w aplikacji, którą opracowuję. Timery nie działają, gdy aplikacja jest w tle, ale aplikacja stale otrzymuje aktualizacje lokalizacji. Czytałem gdzieś w dokumentacji (wydaje mi się, że nie mogę go teraz znaleźć, opublikuję aktualizację, gdy to zrobię), że metodę można wywołać tylko w aktywnej pętli run, gdy aplikacja jest w tle. Delegat aplikacji ma aktywną pętlę run nawet w bg, więc nie musisz tworzyć własnych, aby to działało. [Nie jestem pewien, czy to jest poprawne Wyjaśnienie, ale TAK ZROZUMIAŁEM z tego, co przeczytałem]

Po pierwsze, Dodaj obiekt {[2] } dla klucza UIBackgroundModes w informacji aplikacji.plist. Teraz musisz uruchomić aktualizacje lokalizacji w dowolnym miejscu w aplikacji:

    CLLocationManager locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;//or whatever class you have for managing location
    [locationManager startUpdatingLocation];

Następnie napisz metodę obsługi aktualizacji lokalizacji, powiedz -(void)didUpdateToLocation:(CLLocation*)location, w aplikacji delegat. Następnie zaimplementuj metodę locationManager:didUpdateLocation:fromLocation z CLLocationManagerDelegate w klasie, w której uruchomiłeś menedżera lokalizacji (ponieważ ustawiliśmy delegata menedżera lokalizacji na 'self'). Wewnątrz ta metoda musisz sprawdzić, czy minął przedział czasu, po którym musisz obsługiwać aktualizacje lokalizacji. Możesz to zrobić, zapisując bieżący czas za każdym razem. Jeśli upłynął ten czas, wywołaj metodę UpdateLocation z delegata aplikacji:

NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *lastLocationUpdateTiemstamp;

int locationUpdateInterval = 300;//5 mins

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (userDefaults) {

        lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp];

        if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) {
            //NSLog(@"New Location: %@", newLocation);
            [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation];
            [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp];
        }
    }
}

Spowoduje wywołanie metody co 5 minut, nawet gdy aplikacja jest w tle. Imp: Ta implementacja wyczerpuje baterię, jeśli dokładność danych o lokalizacji nie jest krytyczna, powinieneś użyć [locationManager startMonitoringSignificantLocationChanges]

Przed dodaniem tego do aplikacja, proszę przeczytać Location Awareness Programming Guide

 35
Author: Bushra Shahid,
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-12-05 10:06:34

Teraz, gdy iOS6 jest obecnie najlepszym sposobem na wiecznie działające usługi lokalizacji jest...

- (void)applicationWillResignActive:(UIApplication *)application
{
/*
 Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
 */

NSLog(@"to background");

app.isInBackground = TRUE;

UIApplication *app = [UIApplication sharedApplication];

// Request permission to run in the background. Provide an
// expiration handler in case the task runs long.
NSAssert(bgTask == UIBackgroundTaskInvalid, nil);

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    // Synchronize the cleanup call on the main thread in case
    // the task actually finishes at around the same time.
    dispatch_async(dispatch_get_main_queue(), ^{

        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
}];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

    locationManager.distanceFilter = 100;
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    [locationManager startMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];

    NSLog(@"App staus: applicationDidEnterBackground");
    // Synchronize the cleanup call on the main thread in case
    // the expiration handler is fired at the same time.
    dispatch_async(dispatch_get_main_queue(), ^{
        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
});

NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);

}

Po prostu przetestowałem to w ten sposób:

Uruchomiłem aplikację, przejdź w tle i przenieść w samochodzie o kilka minut. Następnie wracam do domu na 1 godzinę i ponownie zaczynam się poruszać (bez ponownego otwierania aplikacji). Lokacje zaczęły się od nowa. Następnie zatrzymał się na dwie godziny i zaczął ponownie. Wszystko w porządku...

Nie zapomnij skorzystać z nowych usług lokalizacji w iOS6

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{   
    CLLocation *loc = [locations lastObject];

    // Lat/Lon
    float latitudeMe = loc.coordinate.latitude;
    float longitudeMe = loc.coordinate.longitude;
}
 22
Author: Alejandro Luengo,
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
2012-10-08 18:05:38

/ Align = "left" / Mam proste rozwiązanie.

  1. spójrz na ten przykład z raywenderlich.com - > mieć przykładowy kod, działa to doskonale, ale niestety nie ma timera podczas lokalizacji w tle. to potrwa w nieskończoność.
  2. Dodaj timer używając :

    -(void)applicationDidEnterBackground {
    [self.locationManager stopUpdatingLocation];
    
    UIApplication*    app = [UIApplication sharedApplication];
    
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    
     self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
    
    }
    
  3. Tylko nie zapomnij dodać "rejestry aplikacji dla aktualizacji lokalizacji" w info.plist.

 13
Author: HelmiB,
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-06-01 15:41:03

Niestety, wszystkie twoje założenia wydają się poprawne, i nie sądzę, że jest na to sposób. Aby zaoszczędzić czas pracy baterii, usługi lokalizacji iPhone ' a opierają się na ruchu. Jeśli telefon znajduje się w jednym miejscu, jest niewidoczny dla usług lokalizacji.

CLLocationManager zadzwoni tylko locationManager:didUpdateToLocation:fromLocation:, gdy telefon otrzyma aktualizację lokalizacji, co dzieje się tylko wtedy, gdy jedna z trzech usług lokalizacyjnych (Wieża komórkowa, gps, wifi) zauważy zmianę.

Kilka innych rzeczy, które mogą pomóc w poinformowaniu dalsze rozwiązania:

  • Uruchamianie i zatrzymywanie usług powoduje wywołanie metody delegata didUpdateToLocation, ale newLocation może mieć Stary znacznik czasu.

  • Monitorowanie regionu może pomóc

  • Podczas uruchamiania w tle należy pamiętać, że może być trudno uzyskać "pełną" obsługę usług lokalizacyjnych zatwierdzoną przez Apple. Z tego, co widziałem, specjalnie zaprojektowali startMonitoringSignificantLocationChanges jako alternatywę dla małej mocy dla aplikacji, które wymagają lokalizacji w tle wsparcie i zdecydowanie zachęcaj programistów do korzystania z tego, chyba że aplikacja absolutnie tego potrzebuje.

Powodzenia!

Aktualizacja: te myśli mogą być już nieaktualne. Wygląda na to, że ludzie odnieśli sukces z @wjans odpowiedz, powyżej.

 5
Author: Chazbot,
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
2012-08-28 08:59:49

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.

To co zrobiłem to:

Wymagane: Zarejestruj tryb tła dla lokalizacji aktualizacji.

1. Utwórz LocationManger i startUpdatingLocation, z accuracy i filteredDistance 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 na zawsze używając 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. Aplikacja jest aktualizowana jak zwykle za pomocą 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 then locationManager:didFinishDeferredUpdatesWithError: callback do swojego celu

- (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.

 5
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
2015-08-12 07:26:57
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [self.locationManager setAllowsBackgroundLocationUpdates:YES];
}

Jest to potrzebne do śledzenia lokalizacji w tle od systemu iOS 9.

 5
Author: Nilesh,
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-01-13 06:48:34

Oto czego używam:

import Foundation
import CoreLocation
import UIKit

class BackgroundLocationManager :NSObject, CLLocationManagerDelegate {

    static let instance = BackgroundLocationManager()
    static let BACKGROUND_TIMER = 150.0 // restart location manager every 150 seconds
    static let UPDATE_SERVER_INTERVAL = 60 * 60 // 1 hour - once every 1 hour send location to server

    let locationManager = CLLocationManager()
    var timer:NSTimer?
    var currentBgTaskId : UIBackgroundTaskIdentifier?
    var lastLocationDate : NSDate = NSDate()

    private override init(){
        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManager.activityType = .Other;
        locationManager.distanceFilter = kCLDistanceFilterNone;
        if #available(iOS 9, *){
            locationManager.allowsBackgroundLocationUpdates = true
        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.applicationEnterBackground), name: UIApplicationDidEnterBackgroundNotification, object: nil)
    }

    func applicationEnterBackground(){
        FileLogger.log("applicationEnterBackground")
        start()
    }

    func start(){
        if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        } else {
                locationManager.requestAlwaysAuthorization()
        }
    }
    func restart (){
        timer?.invalidate()
        timer = nil
        start()
    }

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        switch status {
        case CLAuthorizationStatus.Restricted:
            //log("Restricted Access to location")
        case CLAuthorizationStatus.Denied:
            //log("User denied access to location")
        case CLAuthorizationStatus.NotDetermined:
            //log("Status not determined")
        default:
            //log("startUpdatintLocation")
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        }
    }
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        if(timer==nil){
            // The locations array is sorted in chronologically ascending order, so the
            // last element is the most recent
            guard let location = locations.last else {return}

            beginNewBackgroundTask()
            locationManager.stopUpdatingLocation()
            let now = NSDate()
            if(isItTime(now)){
                //TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now)
            }
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        CrashReporter.recordError(error)

        beginNewBackgroundTask()
        locationManager.stopUpdatingLocation()
    }

    func isItTime(now:NSDate) -> Bool {
        let timePast = now.timeIntervalSinceDate(lastLocationDate)
        let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL
        return intervalExceeded;
    }

    func sendLocationToServer(location:CLLocation, now:NSDate){
        //TODO
    }

    func beginNewBackgroundTask(){
        var previousTaskId = currentBgTaskId;
        currentBgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
            FileLogger.log("task expired: ")
        })
        if let taskId = previousTaskId{
            UIApplication.sharedApplication().endBackgroundTask(taskId)
            previousTaskId = UIBackgroundTaskInvalid
        }

        timer = NSTimer.scheduledTimerWithTimeInterval(BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false)
    }
}

Zaczynam śledzenie w AppDelegate TAK:

BackgroundLocationManager.instance.start()
 5
Author: hmitkov,
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-06 13:36:42

Użyłem metody xs2bush, aby uzyskać interwał (używając timeIntervalSinceDate) i trochę go rozbudowałem. Chciałem się upewnić, że otrzymuję wymaganą dokładność, której potrzebuję, a także, że nie wyczerpuję baterii, utrzymując radio gps na więcej niż to konieczne.

Utrzymuję, że lokalizacja działa w sposób ciągły z następującymi ustawieniami:

locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locationManager.distanceFilter = 5;
Jest to stosunkowo niski odpływ baterii. Kiedy jestem gotowy, aby uzyskać mój następny okresowy odczyt lokalizacji, najpierw sprawdzam, aby zobaczyć jeśli lokalizacja mieści się w mojej pożądanej dokładności, jeśli jest, to używam lokalizacji. Jeśli nie, to zwiększam dokładność tym:
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter = 0;
Zdobądź moją lokalizację, a gdy już ją zdobędę, ponownie zmniejszę dokładność, aby zminimalizować zużycie baterii. Napisałem pełną próbkę roboczą tego, a także napisałem źródło kodu po stronie serwera, aby zbierać dane o lokalizacji, przechowywać je w bazie danych i umożliwić użytkownikom przeglądanie danych gps w czasie rzeczywistym lub pobieranie i wyświetlanie wcześniej zapisanych tras. Mam klientów dla iOS, android, Windows phone i java me. Wszyscy klienci są natywnie Pisani i wszyscy działają poprawnie w tle. Projekt jest licencjonowany przez MIT. [3]} projekt iOS jest skierowany do iOS 6 przy użyciu podstawowego zestawu SDK iOS 7. Kod znajdziesz tutaj .

Zgłoś problem na GitHubie, jeśli widzisz z nim jakieś problemy. Dzięki.

 4
Author: nickfox,
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-08-09 14:52:51

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

     [self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
     [self.locationManager setDistanceFilter:99999];
Co wydaje się skutecznie wyłączać GPS. Selektor dla 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ż menedżer lokalizacji nie został zatrzymany, backgroundTimeRemaining pozostaje na maksymalnej wartości. To zmniejszyło zużycie baterii od ~10% na godzinę (ze stałą kCLLocationAccuracyBest w tle) do ~2% na godzinę na moim urządzeniu

 2
Author: Amit Shelgaonkar,
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
2015-06-30 17:52:11

Istnieje Cocoapod APScheduledLocationManager , który pozwala na pobieranie aktualizacji lokalizacji w tle co N sekund z żądaną 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.

 2
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:40:56

Kod Roboczy (Cały Kod Krokowy)

Krok 1

  • przejdź do projektu - > możliwości - > tryby tła - > Wybierz aktualizacje lokalizacji.
  • przejdź do Project - > Info - > Dodaj klucz NSLocationAlwaysUsageDescription z opcjonalnym ciągiem znaków.

Krok 2

Dodaj ten kod do AppDelegate.m

@interface AppDelegate ()<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSTimer *timer;
@end

Krok 3 Dodaj ten kod do applicationDidEnterBackground metoda w AppDelegate.m

    - (void)applicationDidEnterBackground:(UIApplication *)application {
        UIApplication *app = [UIApplication sharedApplication];
        __block UIBackgroundTaskIdentifier bgTaskId =
        [app beginBackgroundTaskWithExpirationHandler:^{
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;
        }];

        dispatch_async( dispatch_get_main_queue(), ^{
            self.timer = nil;
            [self initTimer];
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;
        });
    }

- (void)initTimer {
    if (nil == self.locationManager)
        self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;
    [self.locationManager requestAlwaysAuthorization];
    [self.locationManager startMonitoringSignificantLocationChanges];
    if (self.timer == nil) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
                                                      target:self
                                                    selector:@selector(checkUpdates:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}

- (void)checkUpdates:(NSTimer *)timer{
    UIApplication *app = [UIApplication sharedApplication];
    double remaining = app.backgroundTimeRemaining;
    if(remaining < 580.0) {
        [self.locationManager startUpdatingLocation];
        [self.locationManager stopUpdatingLocation];
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {
    NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
    [self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude];
    UIApplication*    app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self initTimer];
    });
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    [self.locationManager stopUpdatingLocation];
    UIApplication *app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    [self initTimer];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Do the work associated with the task
    });
}

-(void)updateLocationWithLatitude:(CLLocationDegrees)latitude
                     andLongitude:(CLLocationDegrees)longitude{
//Here you can update your web service or back end with new latitude and longitude
}
 1
Author: Hari R Krishna,
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-09-06 07:42:25

W iOS 9 i watchOS 2.0 jest nowa metoda Na CLLocationManager, która pozwala żądać bieżącej lokalizacji: CLLocationManager: requestLocation (). To zakończy się natychmiast, a następnie zwraca lokalizację do delegata CLLocationManager.

Możesz użyć NSTimer, aby poprosić o lokalizację co minutę za pomocą tej metody i nie musisz pracować z metodami startUpdatingLocation i stopUpdatingLocation.

Jednak jeśli chcesz przechwytywać lokalizacje na podstawie zmiany X liczniki od ostatniej lokalizacji, wystarczy ustawić właściwość distanceFilter CLLocationManger i do X wywołać startUpdatingLocation ().

 0
Author: Malcolm,
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-17 17:31:36

Dołączone jest szybkie rozwiązanie oparte na:

Zdefiniuj App registers for location updates w info.plist

Utrzymuj cały czas działanie locationManager

Przełącz kCLLocationAccuracy pomiędzy BestForNavigation (przez 5 sekund, aby uzyskać lokalizację) i ThreeKilometers przez resztę okresu oczekiwania, aby uniknąć odwodnienia baterii

Ten przykład aktualizuje lokalizację co 1 min Na Pierwszym Planie i co 15 min W Tle.

Przykład działa dobrze z Xcode 6 Beta 6, działa na urządzeniu z systemem iOS 7.

W aplikacji Delegat (mapView jest opcjonalnym wskazaniem na kontroler mapView)

func applicationDidBecomeActive(application: UIApplication!) {
    if appLaunched! == false { // Reference to mapView used to limit one location update per timer cycle
        appLaunched = true
        var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        var window = appDelegate.window
        var tabBar = window?.rootViewController as UITabBarController
        var navCon = tabBar.viewControllers[0] as UINavigationController
        mapView = navCon.topViewController as? MapViewController
    }
    self.startInitialPeriodWithTimeInterval(60.0)
}

func applicationDidEnterBackground(application: UIApplication!) {
    self.startInitialPeriodWithTimeInterval(15 * 60.0)
}

func startInitialPeriodWithTimeInterval(timeInterval: NSTimeInterval) {
    timer?.invalidate() // reset timer
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getFirstLocationUpdate:"), userInfo: timeInterval, repeats: false)
}

func getFirstLocationUpdate(sender: NSTimer) {
    let timeInterval = sender.userInfo as Double
    timer?.invalidate()
    mapView?.canReportLocation = true
    timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("waitForTimer:"), userInfo: timeInterval, repeats: true)
}

func waitForTimer(sender: NSTimer) {
    let time = sender.userInfo as Double
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    finalTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getLocationUpdate"), userInfo: nil, repeats: false)
}

func getLocationUpdate() {
    finalTimer?.invalidate()
    mapView?.canReportLocation = true
}

W mapView (locationManager wskazuje na obiekt w AppDelegate)

override func viewDidLoad() {
    super.viewDidLoad()
    var appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
    locationManager = appDelegate.locationManager!
    locationManager.delegate = self
    canReportLocation = true
}

  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        if canReportLocation! {
            canReportLocation = false
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
        } else {
            //println("Ignore location update")
        }
    }
 -1
Author: eharo2,
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
2014-08-25 22:59:44