当用户将运行App切换到后台时,系统会更改其运行状态。对大多数的应用
后台状态就是切换为挂起状态(suspended)。挂起应用是提升电池寿命的一种方式,同时系统也会投入更多的系统资源给用户当前正使用的应用。
大多数的应用可以轻易的切换为挂起状态(suspended),但是有些应用因为自身需求的原因会在后台保持运行。一个关于远足的App也许会一直追踪用户的位置,从而可以在地图上展示运动的轨迹。一个音频App也许需要在锁屏后继续播放音乐。其他的一些应用希望在后台下载内容,这样可以缩减给用户展示的时间。当前你需要让你的App保持后台运行,iOS系统会给你有效的帮助,从而不会过度消耗系统资源和电量。这项技术的实现分为以下三种情况:
- 在前台开启了短任务的应用在进入后台时可以请求一段后台运行时间去完成任务。
- 在前台开始下载任务的应用可以下载任务的控制移交给系统,从而在后台任务运行期间可以控制应用的挂起或终止。
- 对于需要在后台运行特殊类型任务的应用可以声明一种或多种后台运行的模式
除非后台任务可以整体提升用户的体验性,否则尽量避免运行后台任务。应用进入后台也许是由于用户切换了另一个App或者锁屏了,所以临时不使用了。以上任一情况都表明了目前用户不需要维持后台任务了。如果依然维持后台任务将会消耗手机的电量,而且用户也会手动关闭应用。因此尽量考虑好是否需要后台任务,尽量避免后台任务运行。
Executing Finite-Length Tasks 执行限定时间的任务
应用切换到后台时,期望尽快停止运行任务,因此可以被系统挂起。如果前台任务在运行中,则需要额外的时间去完成。你可以调用UIApplication
的方法 beginBackgroundTaskWithName:expirationHandler:或者 beginBackgroundTaskWithExpirationHandler:去申请一些额外的运行时间。调用任一方法都会暂时地延迟应用的暂停,提供额外的时间完成任务。完成后台运行的工作时,App可以调用方法endBackgroundTask:通知系统后台任务已完成可以挂起(suspended)。
每次调用方法 beginBackgroundTaskWithName:expirationHandler:或者 beginBackgroundTaskWithExpirationHandler:都会生成一个关联相关任务的唯一token。当你的应用完成一个任务时,必须调用方法endBackgroundTask :
且传入生成的token,让系统知道任务已经完成了。调用endBackgroundTask :
失败会导致结束应用的运行。如果开始任务前你提供了过期处理器,系统会调用这个处理器给你一个机会去结束后台任务,从而避免应用被终止。
You can even follow this pattern while your app is executing in the foreground.
你不需要等到应用进入后台时再指派后台任务。更有用的设计方式是在开始任务前调用方法 beginBackgroundTaskWithName:expirationHandler:或者 beginBackgroundTaskWithExpirationHandler:,任务一旦技术就调用endBackgroundTask:
。即使你的应用在前台运行也可以遵循这种模式。
列表3-1展示了长时间运行任务如何过渡到后台运行。此例子中,请求后台任务方式包含了一个过期处理器,以防止任务会执行太长的时间。这个任务本身被放置到一个异步调度的队列中,因此applicationDidEnterBackground:
可以正常的执行返回。
Listing 3-1 进入后台时开启后台任务
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
注意:开始一个任务时尽量提供一个过期处理器,如果你想知道你的应用在后天还剩余多少运行时间,可以从
UIApplication
的backgroundTimeRemaining的属性中获取。
在过期处理器(expiration handlers)里可以包含需要关闭任务的代码,然而这里面一定不要放执行耗时的代码,因为调用过期处理器时你的应用已经到达运行极限了,执行耗时代码也许会终止应用,基于这个原因,只执行一个轻量的状态清除和任务结束代码。
Downloading Content in the Background 后台下载任务
Implementing Long-Running Tasks 执行长时间运行的任务
Declaring Your App’s Supported Background Tasks
Tracking the User’s Location
Playing and Recording Background Audio
Implementing a VoIP App
Fetching Small Amounts of Content Opportunistically
Using Push Notifications to Initiate a Download
Downloading Newsstand Content in the Background
Communicating with an External Accessory
Communicating with a Bluetooth Accessory
Getting the User’s Attention While in the Background
Understanding When Your App Gets Launched into the Background
Being a Responsible Background App
Opting Out of Background Execution 选择退出后台执行
如果你一点也不想让你的应用在后台执行,你可以显示地在info.plist
中添加keyUIApplicationExitsOnSuspend
(并且设置成YES
)。When an app opts out, it cycles between the not-running, inactive, and active states and never enters the background or suspended states. 当用户按下home键退出应用时,应用的代理方法applicationWillTerminate:被调用,并且在应用终止前有大约5s的时间去清理工作。
强烈不推荐选择退出后台执行,但是某些情况下也许偏向于使用这种选择。尤其是,如果编写后台执行代码会显著增加复杂性,结束应用也许是一种简便的方式。同样,如果你的app消耗了大量的内存并且很难释放,系统也许无论如何都会杀死你的应用以保证其他的应用正常运行。选择结束程序替代切换到后台也许会得到相同的结果,同时还能节省你的开发时间和精力。
For more information about the keys you can include in your app’s Info.plist
file, see Information Property List Key Reference.