- 你需要实现至少一种用户服务。
- 你需要执行一个有限时间长度的任务。
- 你需要通过通知机制告诉用户一些信息你的程序什么时候停止运行。
Listing 3-2 Checking for background support in earlier versions of iOS
UIDevice* device = [UIDevice currentDevice]; |
BOOL backgroundSupported = NO; |
if ([device respondsToSelector:@selector(isMultitaskingSupported)]) |
backgroundSupported = device.multitaskingSupported; |
beginBackgroundTaskWithExpirationHandler:
方法。如果你的应用程序在任务执行过程中被移到后台,或者你的应用程序已经在后台,这个方法会延时应用程序的挂起。这对正在执行重要任务,如向磁盘写用户数据或者从网络服务器下载一个重要文件。
endBackgroundTask:
方法来标记任务结束的地方。
因为应用程序仅被给予有限的时间来完成后台任务,你必须在时间结束前调用这个方法;否则操作系统会终止你的应用程序。为了避免被终止,你也可以在开始任务时提供一个到期处理回掉并在其中调用
endBackgroundTask:
方法。(你可以使用
UIApplication类的
backgroundTimeRemaining这个属性来知道还有多少剩余时间。
)
重要: 一个应用可以有任意数量的任务在同一时间运行。每次你开始一个任务,beginBackgroundTaskWithExpirationHandler:
方法会为该任务返回一个唯一的标示符。你必须在任务时间结束是传递同一个标示符给endBackgroundTask:
方法。
applicationDidEnterBackground:
方法可以正常返回。这里使用
blocks简化了需要维持一些变量的代码,如后台任务的标示符。这里的
bgTask变量是一个类成员变量。
Listing 3-3 Starting a background task at quit time
- (void)applicationDidEnterBackground:(UIApplication *)application |
{ |
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ |
// 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; |
}); |
} |
application:didReceiveLocalNotification:
这个方法会被调用而不会向用户发送通知。
Listing 3-4 Scheduling an alarm notification
- (void)scheduleAlarmForDate:(NSDate*)theDate |
{ |
UIApplication* app = [UIApplication sharedApplication]; |
NSArray* oldNotifications = [app scheduledLocalNotifications]; |
|
// Clear out the old notification before scheduling a new one. |
if ([oldNotifications count] > 0) |
[app cancelAllLocalNotifications]; |
|
// Create a new notification. |
UILocalNotification* alarm = [[UILocalNotification alloc] init]; |
if (alarm) |
{ |
alarm.fireDate = theDate; |
alarm.timeZone = [NSTimeZone defaultTimeZone]; |
alarm.repeatInterval = 0; |
alarm.soundName = @"alarmsound.caf"; |
alarm.alertBody = @"Time to wake up!"; |
|
[app scheduleLocalNotification:alarm]; |
} |
} |
实现 Long-Running 的后台任务
- 在后台播放听觉内容给用户的应用程序,如一个音乐播放程序。
- 需要一直保持用户地理信息的应用程序,如一个导航程序。
- 支持VoIP协议的应用程序。
- 新闻类应用程序,需要下载和推送最新的新闻内容。
- 从附属接收常规更新的应用程序。
声明你的应用程序支持后台任务
audio
—应用程序在后台播放听觉内容给用户。(内容包括流媒体声音或者使用AirPlay播放的视频内容)
- location—需要一直保持用户地理信息的应用程序,即使程序在后台运行
newsstand-content
—支持VoIP协议的应用程序,提供互联网电话服务
external-accessory
—应用程序和一些附属硬件打交道并需要通过External Accessory framework传递一些计划的常规更新。
bluetooth-central
—应用程序和蓝牙设备打交道并需要通过Core Bluetooth framework传递一些计划的常规更新。
bluetooth-peripheral
—应用程序支持通过Core Bluetooth framework进行一些外围的蓝牙通信。
audio
关键字告诉系统框架,他应该继续播放,并且在合适的时机发起一些回调。如果应用程序没有包含这个关键字,任何正在播放的声音会在应用程序移动到后台之后被停止。
- significant-change location服务(推荐)
- Foreground-only location服务
- Background location服务
重要: 开发者被鼓励使用标准服务或者 significant-location change服务。Location服务需要iOS设备上的无线硬件设备(GPS或者网络)一直处于激活状态。 连续运行这些设备会显著地消耗一些电量。如果你的应用不需要向用户提供精确而连续的地理信息,最好的选择是最小化location服务的使用。
- 音乐播放程序
-
支持视频或音频内容通过AirPlay播放的程序
-
VoIP程序
当 UIBackgroundModes
字段中包含 audio
值时,系统的media frameworks会自动阻止相应的程序在进入后台时被挂起。 只要它一直播放声音或者视频内容,程序会继续在后台运行,而一旦程序停止播放,系统就会挂起它。
互联网电话协议 (VoIP) 应用程序允许用户通过互联网而不是移动电话服务来打电话。这种应用程序需要和相关服务器维持一个持久的网络链接 来接收来电或者其他相关数据。系统会允许这些程序被挂起,并替他们监听相关的socket,而不是让他们一直处于唤醒状态。当来电被监测到,系统会唤醒VoIP程序并将socket的控制权返回给它。
配置一个VoIP程序,你需要如下几步:
- 包含UIBackgroundModes字段(带上voip值)在他的Info.plist文件中
-
为VoIP设置一个socket
-
在被移至后台之前,调用
setKeepAliveTimeout:handler:
方法method来设置一个会被定期执行的处理函数。你的应用程序可以使用这个回调函数来处理和服务的通信。 -
配置audio session来处理传输和接受用户的通话。
一个需要下载新的杂志或者报刊的新闻类应用程序可以注册后台进行这些下载。当你的服务器发送一个 推送通知指示有新的内容可用时,系统回去检查你的应用程序是否包含
newsstand-content
如果是,系统会启动程序。
-
禁用后台运行
如果完全不想让你的程序在后台运行,你可以通过添加UIApplicationExitsOnSuspend
字段 (带上YES的属性值) 到你程序的Info.plist
文件中. 当一个应用程序禁用后台运行时,它的运行周期在not-running, inactive和active三种状态中循环,不会进入background或者suspended状态中。当用户按下Home键退出程序时,app delegate的-
applicationWillTerminate:
方法会被调用,并且应用程序有大约5秒的时间来完成清理和退出工作。
-
beginBackgroundTaskWithExpirationHandler:方法
系统默认分配的有限时间为10分钟(从
获知
),但是如果时间到了依然有系统资源而任务还没有执行完毕会继续执行而不会触发到期回调函数。