测试设备:iPhone 5(iOS 7)
我有一个使用RegionMonitoring
和updateLocation
的应用。如果输入了某个区域,则会按预期调用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应用程序注册位置更新
我该如何解决这个问题?
答案 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];