在后台启动UpdateLocations,didUpdateToLocation仅调用10-20次

时间:2013-11-25 08:23:48

标签: ios objective-c iphone core-location cllocationmanager

测试设备:iPhone 5(iOS 7)

我有一个使用RegionMonitoringupdateLocation的应用。如果输入了某个区域,则会按预期调用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应用程序注册位置更新

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:25)

Apple在iOS 7中引入了一项新政策。如果您在应用程序处于后台时调用“startUpdatingLocation”,则iOS 7不再在后台提供位置更新。在这种情况下,只有将应用程序带到前台才能获得更新。

当您使用地理围栏功能时,每次获得RegionEntered / Exited通知处理此通知时,您的应用只需几秒钟。在这几秒钟内,您还可以获得位置更新。在这几秒钟结束后,iOS 7再次暂停您的应用程序。

您可以使用后台任务获得超过几秒钟的时间,但在iOS 7中,Apple还将应用程序在后台运行的时间从10分钟(iOS 6及更早版本)缩短至iOS 7下仅3分钟。看起来这3分钟是应用程序在后台的总时间。这意味着你不能要求iOS 7 10次获得1分钟的背景时间,你总共只能得到3分钟,所以在第3次你要求一分钟之后,你的应用程序不会得到任何背景时间了。

在后台获取位置更新的唯一机会是在应用程序位于前台时调用“startUpdatingLocation”。这很难过,特别是当你只需要响应Region(进入/退出消息)的位置更新时,因为你需要让位置更新一直运行。但是你可以通过将精度值设置为kCLLocationAccuracyThreeKilometers来减少电池使用量。 只有当您真正需要地理坐标时,才需要位置更新并将精度设置为kCLLocationAccuracyBest。 iOS不会为GPS提供kCLLocationAccuracyThreeKilometers值,因此在这种情况下电池使用量会适中。

对于精确度,值kCLLocationAccuracyBestForNavigation似乎也会在IOS 7下引起问题。如果设备未连接到外部电源,则不会使用此值进行任何位置更新。

总而言之,新的iOS 7位置更新政策使得开发某些类型的应用程序变得更加困难。您不必仅在需要时注册位置更新,而是在应用程序的生命周期内注册这些更新。尽管苹果公司对这项新政策的意图可能恰恰相反,但这当然会让电池的耗电速度更快一些。

更新:

经过一些测试后,我找到了解决这个问题的方法。 Apple提供的文档提到,使用重要位置更改API时,即使在后台启动“startUpdatingLocation”,Apps也可以在后台接收位置更新。

我的第一次测试效果不佳。在调用startUpdatingLocation之前,我正在注册我的应用程序,以便在区域监视委托方法中进行重要的位置更新(因此只在需要时才启用此位置服务),但这仍然不会像文档建议的那样在后台提供位置更新。

但是,如果您在启动应用程序后直接开始侦听重要的位置更改(并且永远不会将其关闭),则可以在应用程序处于后台时调用start“startUpdatingLocation”,并在后台接收位置更新。具有“重要位置变化”功能的电池使用情况似乎非常低,因此这可能是大多数应用程序的解决方案。

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

使用"重要的位置更改“API可能有一个缺点:可以在后台启动应用程序(如果iOS在后台终止,以便为其他应用程序重用其内存),无论何时重复且不必要设备已经“显着”移动(根据文档:当细胞塔发生变化时,每5分钟不超过一次)。因此,只有在退出或输入特定区域时才需要激活的应用程序将被启动,并且不仅在这些区域通知有关位置的变化。但我认为这应该比让标准位置更新始终处于活动状态要好得多。

我的iPhone 5s只有1%的时间将电池耗尽且显着位置变化处于活动状态,而标准位置更新处于活动状态且精度设置为3km时,电池耗电量为12%。

希望这可以帮助所有正在努力应对新iOS 7行为的开发人员。

答案 1 :(得分:0)

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

How to run the timer in background of the application?

在后台如果你想继续定位服务而不是你需要设置pausesLocationUpdatesAutomatically标志,标记信息

pausesLocationUpdatesAutomatically flag info

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

检查我的评论 Location service going to "Inactive" state in iPhone 5

对于位置管理器,下面是用于位置更新的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);

你找到的地方

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

答案 2 :(得分:0)

使用didEnterRegion方法中的以下代码重新开始更新

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

}
[_locationManager startUpdatingLocation];