Я пишу приложение, которое требует обновления местоположения в фоновом режиме с высокой точностью и низкой частотой . Решением, похоже, является фоновая задача NSTimer, которая запускает обновления диспетчера местоположения, которые затем немедленно закрываются. Этот вопрос задавали раньше:
Как мне получать фоновое обновление местоположения каждые n минут в моем приложении iOS?
Получение местоположения пользователя каждые n минут после перехода приложения в фоновый режим
iOS Не типичная проблема с таймером отслеживания местоположения в фоновом режиме
Долгосрочный фоновый таймер iOS с фоновым режимом "местоположение"
Постоянная фоновая служба iOS на основе отслеживания местоположения
но мне еще предстоит получить минимальный рабочий пример . Попробовав каждую перестановку принятых выше ответов, я составил отправную точку. Ввод фона:
- (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];
}
и метод делегата:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(@"%@", newLocation);
NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self.locationManager stopUpdatingLocation];
}
Текущее поведение заключается в том, что время backgroundTimeRemaining
уменьшается со 180 секунд до нуля (во время регистрации местоположения), а затем выполняется обработчик истечения срока действия, и дальнейшие обновления местоположения не генерируются. Как изменить приведенный выше код, чтобы получать периодические обновления местоположения в фоновом режиме на неопределенный срок ?
Обновление : я нацелен на iOS 7, и, похоже, есть некоторые свидетельства того, что фоновые задачи ведут себя по-другому:
Ответы:
Похоже,
stopUpdatingLocation
это то, что запускает фоновый сторожевой таймер, поэтому я заменил его наdidUpdateLocation
:[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]; [self.locationManager setDistanceFilter:99999];
который, кажется, эффективно отключает GPS. Селектор фона
NSTimer
становится таким:- (void) changeAccuracy { [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; }
Все, что я делаю, это периодически переключаю точность, чтобы получать координаты высокой точности каждые несколько минут, и, поскольку
locationManager
она не была остановлена,backgroundTimeRemaining
остается на максимальном значении. Это снизило потребление заряда батареи с ~ 10% в час (с постояннымkCLLocationAccuracyBest
в фоновом режиме) до ~ 2% в час на моем устройстве.источник
Я написал приложение, использующее службы определения местоположения, приложение должно отправлять местоположение каждые 10 секунд. И это сработало очень хорошо.
Просто используйте метод allowDeferredLocationUpdatesUntilTraveled: timeout , следуя документу Apple.
Шаги следующие:
Обязательно: Зарегистрируйте фоновый режим для обновления. Местоположение.
1. Создайте LocationManger и startUpdatingLocation с точностью и отфильтрованным расстоянием, как хотите:
-(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. Чтобы приложение постоянно работало с использованием метода allowDeferredLocationUpdatesUntilTraveled: timeout в фоновом режиме, необходимо перезапустить updateLocation с новым параметром, когда приложение переходит в фоновый режим, например:
- (void)applicationWillResignActive:(UIApplication *)application { _isBackgroundMode = YES; [_locationManager stopUpdatingLocation]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [_locationManager setDistanceFilter:kCLDistanceFilterNone]; _locationManager.pausesLocationUpdatesAutomatically = NO; _locationManager.activityType = CLActivityTypeAutomotiveNavigation; [_locationManager startUpdatingLocation]; }
3. Приложение получает updateLocations как обычно с помощью обратного вызова "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. Но вы должны обрабатывать данные в обратном вызове "locationManager: didFinishDeferredUpdatesWithError:" для ваших целей.
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { _deferringUpdates = NO; //do something }
5. ПРИМЕЧАНИЕ. Я думаю, что мы должны сбрасывать параметры LocationManager каждый раз, когда приложение переключается между фоновым / внешним режимом.
источник
allowsBackgroundLocationUpdates = YES
иrequestAlwaysAuthorization
илиrequestWhenInUseAuthorization
. Например: `CLLocationManager * locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.allowsBackgroundLocationUpdates = ДА; [locationManager requestAlwaysAuthorization]; [locationManager startUpdatingLocation]; `Если у вас есть список
UIBackgroundModes
сlocation
ключом, вам не нужно использоватьbeginBackgroundTaskWithExpirationHandler
метод. Это избыточно. Также вы используете его неправильно (см. Здесь ), но это спорный вопрос, поскольку ваш файл plist установлен.Если
UIBackgroundModes location
в списке есть список, приложение будет продолжать работать в фоновом режиме бесконечно долго, покаCLLocationManger
оно работает. Если вы позвонитеstopUpdatingLocation
в фоновом режиме, приложение остановится и больше не запустится.Может быть, вы могли бы позвонить
beginBackgroundTaskWithExpirationHandler
непосредственно перед звонком,stopUpdatingLocation
а затем после звонкаstartUpdatingLocation
вы могли бы позвонить,endBackgroundTask
чтобы он оставался на связи, пока GPS отключен, но я никогда не пробовал этого - это просто идея.Другой вариант (который я не пробовал) - оставить диспетчер местоположения работающим в фоновом режиме, но как только вы получите точное местоположение, измените
desiredAccuracy
свойство на 1000 м или выше, чтобы позволить чипу GPS отключиться (для экономии заряда батареи). Затем через 10 минут, когда вам понадобится еще одно обновление местоположения, измените значениеdesiredAccuracy
назад на 100 м, чтобы включить GPS, пока не получите точное местоположение, повторите.Когда вы звоните
startUpdatingLocation
менеджеру по местоположению, вы должны дать ему время, чтобы занять позицию. Не стоит сразу звонитьstopUpdatingLocation
. Мы даем ему поработать максимум 10 секунд или пока не получим некэшированное высокоточное местоположение.Вам необходимо отфильтровать кэшированные местоположения и проверить точность полученного местоположения, чтобы убедиться, что оно соответствует минимально необходимой точности (см. Здесь ). Первое обновление, которое вы получите, может быть давным через 10 минут или 10 дней. Первая точность, которую вы получите, может быть 3000 м.
Вместо этого рассмотрите возможность использования API значительного изменения местоположения. Как только вы получите уведомление о значительном изменении, вы можете начать
CLLocationManager
в течение нескольких секунд, чтобы получить положение с высокой точностью. Я не уверен, я никогда не пользовался услугами значительного изменения местоположения.источник
CoreLocation
Ссылка Apple, кажется, рекомендует использоватьbeginBackgroundTaskWithExpirationHandler
при обработке данных о местоположении в фоновом режиме: «Если приложению iOS требуется больше времени для обработки данных о местоположении, оно может запросить дополнительное время выполнения в фоновом режиме с помощью метода beginBackgroundTaskWithName: expirationHandler: класса UIApplication». - developer.apple.com/library/ios/documentation/UserExperience/…locationManagerDidPauseLocationUpdates
. Я проверял это поведение 10 раз!Когда пришло время запустить службу определения местоположения и остановить фоновую задачу, фоновая задача должна быть остановлена с задержкой (достаточно 1 секунды). В противном случае служба определения местоположения не запустится. Также службу определения местоположения следует оставить включенной на пару секунд (например, 3 секунды).
Существует cocoapod APScheduledLocationManager, который позволяет получать фоновые обновления местоположения каждые n секунд с желаемой точностью определения местоположения.
let manager = APScheduledLocationManager(delegate: self) manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
Репозиторий также содержит пример приложения, написанного на Swift 3.
источник
Как насчет того, чтобы попробовать с
startMonitoringSignificantLocationChanges:
API? Он определенно стреляет с меньшей частотой и достаточно хорошей точностью. Кроме того, у него намного больше преимуществ, чем у другихlocationManager
API.Подробнее об этом API уже говорилось по этой ссылке.
источник
This interface delivers new events only when it detects changes to the device’s associated cell towers
Вам нужно добавить режим обновления местоположения в свое приложение, добавив следующий ключ в свой info.plist.
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
didUpdateToLocation
будет вызван метод (даже если ваше приложение находится в фоновом режиме). Вы можете делать что угодно на основе вызова этого методаисточник
После iOS 8 произошли некоторые изменения в фоновой выборке и обновлениях CoreLocation framework, сделанные Apple.
1) Apple представила запрос AlwaysAuthorization для получения обновления местоположения в приложении.
2) Apple представляет backgroundLocationupdates для получения местоположения из фона в iOS.
Для получения местоположения в фоновом режиме вам необходимо включить обновление местоположения в возможностях 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 } }
источник
Чтобы использовать стандартные службы определения местоположения, когда приложение работает в фоновом режиме, вам необходимо сначала включить фоновые режимы на вкладке «Возможности» в настройках цели и выбрать «Обновления местоположения».
Или добавьте его прямо в Info.plist .
<key>NSLocationAlwaysUsageDescription</key> <string>I want to get your location Information in background</string> <key>UIBackgroundModes</key> <array><string>location</string> </array>
Затем вам нужно настроить CLLocationManager
Цель 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()
Ссылка: https://medium.com/@javedmultani16/location-service-in-the-background-ios-942c89cd99ba
источник
locationManager.allowsBackgroundLocationUpdates = true
источник