我们目前正在开发一款需要在后台查看位置的iOS应用。起初,我们尝试使用重要的位置更改,但它们不够准确/不经常触发。我们考虑过使用区域监控,但是从我在线阅读的内容来看,这并不总是准确的,而且您还有一些问题需要监控的区域数量有限。 (我们最终可能会尝试区域监控。)但是,目前我们正在尝试使用标准位置更新来跟踪后台的用户位置,计划每隔5分钟检查一次,左右。
该应用已在后台注册了位置更新(使用'应用寄存器进行位置更新'用于'所需的后台模式'),我们启动后台任务检查位置一旦停止位置更新,然后使用NSThread sleepForTimeInterval:
(此时,我们正在开发中)暂停任务10秒钟。然后再次检查位置,停止位置更新,暂停10秒等等。
这似乎按预期工作...当应用程序进入后台时,我们会每隔10秒收到一次日志/通知,其中我们的位置更新,当重新打开应用程序时,日志/通知会停止。然而,问题是,当应用程序第二次进入后台时,看起来原始后台任务从未被取消,并且创建了一个新任务,因此现在有两个任务在运行,每个任务在10秒时检查位置每隔一段时间如果应用程序多次打开/发送到后台,则会为每个应用程序启动后台任务。
我考虑过设置一个标记来说"应用程序是否至少被发送到后台一次?",并且只有在第一次执行任务时才运行该任务?'发送到后台,但这似乎会导致其他问题,并且(作为一个相对较新的iOS开发人员)我很好奇为什么当应用程序进入前台时后台任务没有被取消。 / p>
AppDelegate.h文件包含...
@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate> {
UIWindow *window;
UINavigationController *navigationController;
UIBackgroundTaskIdentifier bgTask;
BOOL inBackground;
}
AppDelegate.m文件包含...
- (void)applicationDidEnterBackground:(UIApplication *)application {
inBackground = YES;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (inBackground == YES) {
NSLog(@"%@", @"Check location...");
[locationManager startUpdatingLocation];
[NSThread sleepForTimeInterval:10];
}
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
inBackground = NO;
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
位置更新按预期工作,我无法解决为什么当应用进入前台时后台任务没有被取消/结束的原因。我确实想知道它是否与NSThread sleepForTimeInterval:
有关,但我不确定它是不是,或者如何修复它(如果确实如此)。在此先感谢您的帮助!
答案 0 :(得分:2)
您不通过休眠然后请求它们来管理位置更新。您可以通过在UIBackgroundMode
中设置“位置”(与您一样)来管理位置更新,然后实施CLLocationManagerDelegate
。这与beginBackgroundTaskWithExpirationHandler:
无关。这是为了请求额外的时间(最多约10分钟)来完成给定的操作。你根本不应该打电话来获取位置更新。
在UIBackgroundMode
注册为位置信息应用后,只要位置发生变化,您就会自动获得更新,而这些更改的位置管理器指定的准确度。系统将为您完成所有工作。
您所描述的内容实际上可能会损害电池寿命,因为它会影响操作系统管理多个位置传感器的能力(GPS只是其中之一)。通过设置正确的准确度(如果重大变化太粗糙)告诉操作系统您需要什么,并让它完成它的工作。从GPS获得真正准确的位置是昂贵的。你应该先进行电池测试,然后再假设每5分钟做一次比离开更便宜。您可以做的最好的事情就是降低所需的精确度。您可以将其调低到粗略水平,然后当您到达前景时将其移动到准确的水平。但是,跟踪精确用户每5分钟的位置将会很昂贵。很难解决这个问题。
顺便说一下,你真正想做的就是每5分钟运行一次“东西”。在iOS中没有这种机制。您可以询问是否提供位置服务(并以各种方式配置它)。你不能要求“我想每隔五分钟醒来......并做任何事情。”大约10分钟后,如果你不打电话endBackgroundTask:
,你就会被杀死。
关于为什么没有取消任务的问题,请参阅How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS。正如我所说,这个“后台任务”不是你想要解决这个问题的工具。这完全不相关。
答案 1 :(得分:1)
我非常确定当应用程序返回到前台时,您的实例变量bgTask
正在被重新分配,因此该值不包含您要杀死的标识符。请考虑将此标识符保存在NSUserDefaults
或更永久的内容中,并在以后检索它。