几秒钟后,ios7中的操作系统杀死了应用程序
我正在为iOS 7创build基于导航的应用程序,因为我正在使用用户位置数据,使用CoreLocation框架,
应用程序的要求是在特定的时间开始获取用户在后台的位置,为此,我已经使用didReceiveRemoteNotification fetchCompletionHandler:
方法实现了无声Pushnotification,
我已经成功地实现了这个使用无声Pushnotification及其调用startUpdatingLocation
,我能够获取委托方法中的位置数据:
使用这个有效载荷:
{"aps" : {"content-available" : 1},"SilentPush" : "4"}
我已启用背景模式的location
和remote notification
:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler { __block UIBackgroundTaskIdentifier bgTask =0; UIApplication *app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [self.locationManager startUpdatingLocation]; }];
didUpdateLocations
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { lastLoc=[locations lastObject]; [logFile addLocObject:[NSString stringWithFormat:@"Loc: %@",lastLoc]]; }
但问题是:
在几秒钟后,位置类的委托方法被停止,如果设备正在移动,它将不会发送任何数据。而当我说应用程序前景时,它会调用“didFinishLaunhing”方法,所以我猜os会杀死应用程序甚至位置正在更新,在设备Diagnostics & usage
我收到以下崩溃报告:
Application Specific Information: MockUpApp2[390] has active assertions beyond permitted time: {( <BKProcessAssertion: 0x145ac790> identifier: Called by MockUpApp2, from -[AppDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] process: MockUpApp2[390] permittedBackgroundDuration: 40.000000 reason: finishTaskAfterBackgroundContentFetching owner pid:390 preventSuspend preventIdleSleep preventSuspendOnSleep )}
昨天我已经问了这个问题,现在我可以通过推送通知在后台启动位置pipe理器,
所以请任何人都可以解决这个问题。
谢谢。
注:如果我在debugging模式下运行应用程序,意味着我通过XCode运行应用程序,而不是停止或不断开,应用程序将运行..在这种情况下,应用程序不会停止的操作系统。
编辑1
根据@Stephen Darlington答案如果我删除所有的backgroundfatcher像,
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler { [self.locationManager startUpdatingLocation]; }
现在应用程序不会调用didUpdateLocations
一次,:(
我应该用这种方法写什么?
Edit 2
根据苹果医生说:
If your app is suspended or not running, the system wakes up or launches your app and puts it into the background running state before calling the method.
所以,应用程序应该在后台运行,只要我启用位置背景模式 ,?
我不认为iOS上的后台处理工作的方式,你所期望的。 这不像在Mac或Windows上,你可以在后台无限期运行(即使在iOS 7的变化)。
所以,直接回答你的问题:你启动了一个可以继续在后台运行的任务。 有两个“buts”。
- 代码块是到期处理程序 。 这不是你想要在后台运行的代码。 这个代码会在后台任务超时之前得到执行(所以在你的应用程序被终止之前就会被执行)。 苹果公司并没有真正logging多久,但它看起来好像你是大约40秒。 您想要在后台运行的代码是
beginBackgroundTaskWithExpirationHandler
之后的beginBackgroundTaskWithExpirationHandler
。 当你完成你说endBackgroundTask:
- 其次,位置更新在后台工作,没有所有的
beginBackgroundTaskWithExpirationHandler:
东西。 即使应用程序在后台,委托方法也会被调用
总结一下:删除beginBackgroundTaskWithExpirationHandler:
语句。 你只需要添加startUpdatingLocation:
前段时间我在CLLocation上做了不less工作,我也有一些意见和build议,也许还不完整。
我看到你正在对beginBackgroundTaskWithExpirationHandler
块中的无声通知beginBackgroundTaskWithExpirationHandler
反应。 我不认为这是正确的。 但是我相信你应该在CLLocationDelegate方法上使用backgroundTask模式。
更重要的是,苹果很有可能会拒绝你使用位置标志进行后台进程。 从我的经验。 我花了大量的时间来体面地使用定位服务,以提高我自己的stream程的准确性。 我甚至启用了许多防止电池过度使用的保护措施,他们没有经过讨论就拒绝了。 我做了它,所以它只在设备插入充电器时使用后台服务。 我上诉,并提出了一个好的案件负责使用,无济于事。
你应该查看条款,并确保你的用例正好符合规定,否则将不会浮动。
我仍然说,没有后台服务,你可以得到你想要的东西。 使用重要的位置更改和区域监控,您的应用程序将不需要任何东西,只需保存最新的已知位置并响应通知。
我会想到一个这样的计划:
- 重要的位置变化事件进来。检查速度/活动。 你可以做到这一点,而不启用后台服务。
- 如果开车只是保存位置。 开车时你会经常变化,所以你只会在后面分钟。
- 不开车或闲置,根据您的准确性要求创build一个合理大小的区域。 只要设备在该地区,就可以使用当前保存的最近位置。 这将是整个24小时内的大部分时间,所以你总体上对电池的影响很小。
在我看来,你是以错误的观点来看待这个问题的。 这是合乎逻辑的,认为你会发送消息,然后通过使CL做些事情来做出回应。 这不是服务的目的。 本质上,您设置了位置pipe理器并放行。
您可能会从GitHub上存储库中使用的某些模式中受益。
TTLocationHandler
它在一年内没有更新,我不记得我所学到的全部内容,但是它为我提供了坚实的基础,因为我没有必要捣鼓它。
在这个例子之后,您将停止并启动,或者切换到区域或显着的位置变化监视所有基于应用程序状态。 不需要交互。
您的位置事件将在处理过程中进行处理,无论是否为背景。
在您的远程通知回复中,您只能阅读最新的位置信息或任何您需要的信息,并根据您的意愿采取行动。 您不要在这里调用startUpdatingLocation。 如果您在后台使用位置服务,则不应首先将其停止。
编辑 – 正确使用到期处理程序块
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { __block UIBackgroundTaskIdentifier bgTask =0; UIApplication *app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ // Do something here. Perhaps you'll log the error or respond with some fall back // This block will only be run if the handler expires without having been ended // In that case, you need to end it now or you will crash If (bgTask != UIBackgroundTaskInvalid) { [app endBackgroundTask:bgTask]; [bgTask = UIBackgroundTaskInvalid]; } }]; // This is where the code you intend to run in the background starts [self.locationManager startUpdatingLocation]; // Now tell the system you are finished, ending background task normally before exit If (bgTask != UIBackgroundTaskInvalid) { [app endBackgroundTask:bgTask]; [bgTask = UIBackgroundTaskInvalid; } }
方法beginBackgroundTaskWithExpirationHandler:
给应用程序时间到它的东西,但这并不意味着任务可以永远运行。
如应用程序崩溃日志中所述,您的应用程序已被清除,因为您的时间显然已经耗尽。
你应该得到相同的结果只是要求位置更新,而不包裹到期处理程序。
我记得在旧系统中,我通过使用区域监视来触发背景中的位置更新来pipe理类似的东西。
[编辑]
为了获得最好的结果,而玩的位置,我build议你使用真实的设备,也许你是。