后台的StartUpdateLocations,didUpdatingToLocation只调用了10-20次

testing设备:iPhone 5(iOS 7)

我有一个使用RegionMonitoringupdateLocation的应用程序。 如果input区域, didEnterRegion预期调用didEnterRegion 。 然后我打电话给startUpdatingLocation 。 但是方法didUpdateToLocation只被调用10-20次,而它应该更新的位置,直到定时器触发。

相关代码:

 CLLocationManager *_locationManager; NSTimer *_timer; -(void)initLocationManager { _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; [_locationManager setActivityType:CLActivityTypeOther]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation]; [_locationManager setPausesLocationUpdatesAutomatically:NO]; [_locationManager setDistanceFilter:kCLDistanceFilterNone]; } //Did Enter Region, called as expected: - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { [_locationManager startUpdatingLocation]; _timer = [NSTimer scheduledTimerWithTimeInterval:300.0f target:self selector:@selector(scheduleMethod:) userInfo:nil repeats:NO]; } //Timer Fire Method: - (void) scheduleMethod:(NSTimer*)timer { [Utils writeToLog:@"Timer-Stop"]; [_locationManager stopUpdatingLocation]; } //This Method only called 10-20 Times (in the first 10-20 Seconds) and not the complete 5 Minutes: - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { [Utils writeToLog:@"LocationUpdate!"]; } 

到目前为止,我尝试过:重新启动位于locationManagerDidPauseLocationUpdates方法中的更新,但似乎永远不会被调用:

 -(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager { [WRUtils writeToLog:@"LocationUpdate paused, restarted"]; [_locationManager startUpdatingLocation]; } 

检查didFailWithError方法中的错误,但不会调用它。 并玩了一下属性:

 [_locationManager setActivityType:CLActivityTypeOther]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation]; [_locationManager setPausesLocationUpdatesAutomatically:NO]; 

Plist设置是正确的我猜:所需的背景模式是所需的背景模式项目0应用程序注册位置更新

我该如何解决这个问题?

苹果已经在iOS 7中引入了一项新政策。如果您在应用程序处于后台时调用“startUpdatingLocation”,则iOS 7不会在后台传递位置更新。 在这种情况下,只有当应用程序处于前台时,才会进行更新。

当您使用地理围栏function时,每当您收到RegionEntered / Exited通知来处理此通知时,您的应用程序只需几秒钟。 在这几秒钟内,你也可能会得到位置更新。 这几秒钟后,iOS 7只是暂停您的应用程序。

你可以使用后台任务来获得更多的时间,但是在iOS 7中,苹果公司已经将应用程序在10分钟内(iOS 6和更早版本)在后台运行的时间减less到只有3分钟。这3分钟是整个应用程序在后台的总时间。 这意味着你不能要求iOS 7 10次获得1分钟的背景时间,你只会得到3分钟的总时间,所以在第三次问你一分钟后,你的应用程序将不会获得任何背景时间了在所有。

在后台获取位置更新的唯一机会是在应用处于前台时调用“startUpdatingLocation”。 特别是当您只需要位置更新以响应区域(input/输出消息,因为您需要让位置更新始终运行),但是您至less可以通过将准确度值设置为kCLLocationAccuracyThreeKilometers来减less电池使用你不需要进行位置更新,只有当你确实需要地理坐标时,才能将精确度设置为kCLLocationAccuracyBest。iOS不会为kCLLocationAccuracyThreeKilometers值启动GPS,所以在这种情况下电池的使用量是适中的。

此外,值为kCLLocationAccuracyBestForNavigation准确性似乎导致IOS 7下的问题。如果设备没有连接到外部电源,我没有得到任何位置更新此值。

总而言之,所有新的iOS 7的位置更新策略使开发某些types的应用程序变得更加困难。 而不是只在需要的时候注册位置更新,你不得不在你的应用程序的生命周期中注册这些。 尽pipe苹果公司对这一新政策的内涵可能是相反的,但是这当然会更快一点。

更新:

经过一些更多的testing,我发现了一些解决scheme。 苹果的文档提到,使用重要位置更改API时,即使在后台启动“startUpdatingLocation”,应用程序也可以在后台接收位置更新。

我的第一个testing不能很好地工作。 我刚刚在调用startUpdatingLocation(因此只在需要时才启用此位置服务)之前,在区域监视委托方法中注册我的应用程序以进行重要的位置更新,但是这仍然不会像文档build议的那样在后台传递位置更新。

但是,如果您在启动应用程序后立即开始监听重大的位置更改(并且决不会将其closures),则可以在应用程序处于后台时调用启动“startUpdatingLocation”,并在后台接收位置更新。 具有“显着位置变化”function的电池使用量似乎非常低,所以这可能是大多数应用程序的解决scheme。

您必须检查设备上是否有“重大位置更改”function,但目前所有设备似乎都支持这一function。 即使是第五代iPod Touch也支持它(iPod Touch不能使用手机信号塔进行位置更新,根据苹果的文档,这是该function的基本方法,所以我想我们可以假设所有运行iOS的设备7可以使用“重要的位置更新”API,虽然这可能是一个好主意,检查这个function是否真的可用,也许有某些情况下function不可用)。

使用“重要的位置更改”API可能有一个缺点:应用程序可以在后台启动(如果它在后台被iOS终止,以重用其他应用程序的内存)反复和不必要的每当设备已移动“显着“(根据文档:当手机信号塔发生变化时,每5分钟不超过一次),所以只有当某个区域退出或进入时才需要激活的应用程序将会启动并通知有关位置变化所有的时间,不仅在这些地区,但我认为这应该比标准的位置更新一直活跃好多了。

我的iPhone 5s的电池只有1%的电量消耗了大量的位置变化,而不是12%的标准位置更新,精度设置为3公里。

希望这有助于所有正在为新iOS 7行为而苦恼的开发人员。

在后台定时器不会运行,所以在这里你的定时器对象不会响应,你需要创build后台任务处理程序,检查下面的链接的评论,

如何在应用程序的后台运行计时器?

在后台如果你想继续位置服务比你需要设置暂停位置更新自动标志,标志信息

pausesLocationUpdatesAutomatically标志信息

  if ([self.locationManager respondsToSelector:@selector(pausesLocationUpdatesAutomatically)]) { self.locationManager.pausesLocationUpdatesAutomatically = NO; } 

检查我的评论定位服务在iPhone 5进入“无效”状态

对于位置pipe理器,下面是用于位置更新的CLLocationManagerDelegate方法,

  - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation [Deprecated in __IPHONE_6_0] - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0); 

你在哪里find的

  - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation ?? 

在你的didEnterRegion方法中使用下面的代码再次开始更新

 [_locationManager startMonitoringSignificantLocationChanges]; if ([_locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { _locationManager.allowsBackgroundLocationUpdates =YES; } [_locationManager startUpdatingLocation];