Обновление местоположения в фоновом режиме и приостановленных режимах приложения

Я хочу написать приложение, которое каждые 5 минут отправляет серверу низкоточное местоположение для обоих режимов: переднего плана и фона. Поскольку я не хочу уменьшать заряд батареи, а locationSignificantChange дает только значения с высокой точностью, я запускаю/останавливаю местоположениеОбновление от GPS каждые 5 мин. Приложение работает отлично от режима переднего плана, но работает только около 1 часа из фонового режима (и останавливается, чтобы отправить местоположение после этого). Я думаю, что я пропускаю что-то в backgroundTask/NSTimer, потому что я новичок в iOS. Я буду очень благодарен за вашу помощь. Приложение будет работать только для iOS 7 и выше.

В общем, мой алгоритм:

** start backGroundTask
** [_locationManager startUpdatingLocation]
** handle received location in "didUpdateLocations:" listener
** [_locationManager stopUpdatingLocation]
** create new thread and fire the NSTimer with delay 5 min
** end backGroundTask

Это мой код:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [self startLocationManager];
        // .. other init app code
}



- (void) startLocationManager {
          _locationManager = [[CLLocationManager alloc] init];
          _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
          _locationManager.distanceFilter = 10;
          _locationManager.delegate = self;
          _locationManager.pausesLocationUpdatesAutomatically = NO;
          [_locationManager startLocation];
}



- (void) startLocation {
    UIApplication * app = [UIApplication sharedApplication];
    self.bkgdTask = [app beginBackgroundTaskWithExpirationHandler:^{
    }];
    [self.locationManager startUpdatingLocation];
}



- (void) stopUpdatingLocation {

    [_locationManager stopUpdatingLocation];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
       self.locationNextTimer =  [NSTimer scheduledTimerWithTimeInterval:5 * 60
                                                                 target:self
                                                                 selector:@selector(startLocation)
                                                                 userInfo:nil
                                                                 repeats:NO];
        [[NSRunLoop currentRunLoop] addTimer:self.locationNextTimer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
        [app endBackgroundTask:self.bkgdTask];
        self.bkgdTask = UIBackgroundTaskInvalid;
     });
}



- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
       [self.locationNextTimer invalidate];
       self.locationNextTimer = nil;
       //ToDo  Location Handling
       [self stopUpdatingLocation];
}

EDIT:

Как я понял из iOS7 Apple хочет, чтобы startUpdatingLocation для locationManager выполнялся только с переднего плана. Итак, любые идеи для решения этой проблемы? Я также попробовал дополнительное решение: вместо stop/startUpdatingLocation с NSTimer, чтобы изменить точность и расстояниеFilter для больших/малых значений с помощью NSTimer. Это не сработало, потому что я получаю триггер в "didUpdateLocations:" прослушиватель 4 раза для "freeway drive" вместо одного раза.

Ответ 1

Менеджер местоположений будет определять для себя наименьшее действие, основанное на ваших настройках. Задайте параметры, подходящие для вашего прецедента, а затем ответственно ответьте в своем делетете. Проверьте полученные местоположения, если они слишком свежи, и вы ничего не делаете. Это позволит вашей обработке приложений воздействовать на аккумулятор как можно меньше.

significantLocationChanges предназначен для снижения воздействия, и, по моему опыту, он неплохо справляется с этим. Другой вариант - использовать мониторинг региона или вместе с ним.

Вы можете дополнительно ограничить активность, создав области размера, основанные на точности, которую вы хотите достичь. Обновление регионов и сохранение местоположения только по мере пересечения границ. Это может быть более подходящим для ваших нужд.

Ответ 2

Чтобы получить обновление местоположения, когда приложение находится в фоновом режиме, и когда приложение приостановлено, это 2 очень разных сценария. Вам придется обращаться с ними по-другому.

Чтобы получить обновление местоположения, когда

A) Приложение находится в фоновом режиме, см. раздел Справочные службы, не работающие в iOS 7

B) Приложение приостановлено/завершено, см. Как получить обновления местоположения для iOS 7 и 8 Даже при приостановке приложения

Исходные коды для вышеуказанного сценария доступны в GitHub.