StartUpdateLocations in Background, did更新到Location 只调用 10-20 次



测试设备: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方法中的Updates,但似乎从未调用过:

-(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将不再在后台提供位置更新。在这种情况下,只有当应用程序处于前台时,您才能获得更新。

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

你可以使用后台任务获得几秒钟以上的时间,但在iOS 7中,苹果还将应用程序在后台运行的时间从10分钟(iOS 6及以上版本)减少到了iOS 7下的3分钟。看起来这3分钟是应用程序在后台的整个时间的总和。这意味着你不能要求iOS 7 10次获得1分钟的背景时间,你总共只能获得3分钟,所以在你第三次要求一分钟后,你的应用程序将不再获得任何背景时间。

您在后台获取位置更新的唯一机会是在应用程序处于前台时调用"startUpdatingLocation"。这很令人难过,尤其是当您只需要对Region进行位置更新时(输入/退出消息,因为您需要让位置更新一直运行。但当您不需要位置更新,只在真正需要地理坐标时才将精度设置为kCLLocationAccuracyBest。iOS不会为kCLLocationAccuracyThreeKilometers值打开GPS电源,因此在这种情况下电池使用量会适中。

此外,kCLLocationAccuracyBestForNavigation的精度值似乎会在IOS7下引发问题。如果设备未连接到外部电源,我不会得到任何具有此值的位置更新。

总而言之,iOS 7关于位置更新的新政策使开发某些类型的应用程序变得更加困难。您不是只在需要时注册位置更新,而是被迫在应用程序的使用寿命内注册位置更新。当然,这会更快地消耗电池,尽管苹果对这项新政策的意图可能恰恰相反。

更新:

经过更多的测试,我找到了解决这个问题的方法。苹果公司的文档提到,当使用重大位置变更API时,即使"startUpdatingLocation"在后台启动,应用程序也可以在后台接收位置更新

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

但是,如果你在应用程序启动后直接开始监听显著的位置变化(并且永远不要关闭),当应用程序处于后台时,您可以调用start"startUpdatingLocation",也可以在后台接收位置更新。始终启用"重大位置更改"功能的电池使用率似乎很低,因此这可能是大多数应用程序的解决方案。

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

使用"显著位置变化"API可能有一个缺点:每当设备"显著"移动时,应用程序可以在后台重复启动(如果iOS在后台终止应用程序以将其内存用于其他应用程序)(根据文档:当蜂窝塔发生变化时,但每5分钟不超过一次)。因此,当退出或进入某个区域时,只需要激活的应用程序将一直启动并通知位置更改,而不仅仅是在这些区域。但我认为这应该比一直激活标准位置更新要好得多。

我的iPhone 5s在激活显著位置更改的情况下,夜间电池电量仅消耗1%,而在激活精度设置为3公里的标准位置更新的情况下消耗12%。

希望这能帮助所有正在与新的iOS 7行为作斗争的开发人员。

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

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

在后台,如果你想继续定位服务,你需要设置pausesLocationUpdates自动标记,在上标记信息

pausesLocationUpdates自动标记信息

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

查看我对的评论定位服务将转到";不活动";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 ??

didEnterRegion方法中使用以下代码再次开始更新

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

相关内容

最新更新