判断是否支持多线程
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;
声明你需要的后台任务
Info.plist中添加UIBackgroundModes键值,它包含一个或多个string的值,包括
audio:在后台提供声音播放功能,包括音频流和播放视频时的声音
location:在后台可以保持用户的位置信息
voip:在后台使用VOIP功能
前面的每个value让系统知道你的应用程序应该在适当的时候被唤醒。例如,一个应用程序,开始播放音乐,然后移动到后台仍然需要执行时间,以填补音频输出缓冲区。添加audio键用来告诉系统框架,需要继续播放音频,并且可以在合适的时间间隔下回调应用程序;如果应用程序不包括此项,任何音频播放在移到后台后将停止运行。
除了添加键值的方法,IOS还提供了两种途径使应用程序在后台工作:
Task completion—应用程序可以向系统申请额外的时间去完成给定的任务
Local notifications—应用程序可以预先安排时间执行local notifications 传递
实现长时间的后台任务
应用程序可以请求在后台运行以实现特殊的服务。这些应用程序并不连续的运行,但是会被系统框架在合适的时间唤醒,以实现这些服务
1、
2、
添加UIBackgroundModes中audio值,注册后台音频应用。这个值使得应用程序可以在后台使用可听的背景,如音乐播放或者音频流应用。对于支持音频和视频功能的应用程序也可以添加该值以保证可以继续持续的运行流。
当audio值设置后,当你的应用程序进入后台后,系统的多媒体框架会自动阻止它被挂断,但是,如果应用程序停止播放音频或者视频,系统将挂断应用程序。
当你的应用程序在后台时,你可以执行任意的系统音频框架去初始化后台音频。你的应用程序在后台时应该限制自身,使其执行与工作相关的代码,不能执行任何与播放内容无关的任务
由于有多个应用程序支持音频,前台的应用程序始终允许播放音频,后台的应用程序也被允许播放一些音频内容,这取决于audio session object的设置。应用程序应该始终设置它们的audio session object,并小心的处理其他类型的音频相关notifications和中断。详见audio session programming guide。
3、
VOIP程序需要稳定的网络去连接和它相关的服务,这样它才能接到来电和其他相关的数据。系统允许VOIP程序被挂断并提供组件去监听它们的sockets,而不是在任意时候都处于唤醒状态。设置VOIP应用程序如下:
A、 添加UIBackgroundModes中的VOIP键值
B、 为VOIP设置一个应用程序socket
C、 在移出后台之前,调用setKeepAliveTimeout:handler:方法去建立一个定期执行的handler,你的应用程序可以运行这个handler来保持服务的连接。
D、 设置你的audio session去处理这种切换
释义:
A、 大多数VOIP应用需要设置后台audio 应用去传递音频,因此你应该设置audio 和voip两个键值。
B、 为了使应用程序在后台时保持稳定的连接,你必须tag你的主通讯socket专门应用于VOIP,tagging这个socket来告诉系统,它必须在你的应用程序中断时接管这个socket。这个切换本身对于你的应用程序时透明的,当新的数据到达socket的时候,系统会唤醒应用程序,并将socket的控制权返回给应用程序,这样应用程序就可以处理新来的数据。
你只需要tag用于voip服务的socket,这个socket用来接收来电或者其他相关的数据来保持你的VOIP服务的连接。根据收到的信息,这个socket要决定下一步的动作。比如一个来电,你会想弹出一个本地的通知来告知用户;对于其他不是那么关键的数据,你可能会想悄悄的处理这些数据并让系统将应用程序重新中断。
在IOS中,sockets是用流或者更高级的结构,设置一个VOIP的socket,你只需要在通常的设置中添加一个特殊的key来标明这个接口是用于连接VOIP服务的,下表列出了流的接口和设置:
设置流接口用于voip | |
接口 | 设置 |
NSInputStream 和 NSOutputStream | 对于 Cocoa streams, 使用setProperty:forKey: 方法添加 NSStreamNetworkServiceTy |
NSURLRequest | 对于 URL loading system, 使用setNetworkServiceType: method of your NSMutableURLRequest object to set the network service type of the request. The service type should be set to NSURLNetworkServiceTypeV |
CFReadStreamRef和 CFWriteStreamRef | For Core Foundation streams, use the CFReadStreamSetProperty or CFWriteStreamSetProperty ServiceType property to the stream. The value for this property should be set to kCFStreamNetworkServiceT |
(注意:当设置socket的时候,你需要在你的主信号通道中设置合适的service type key。当设置声道时,不需要设置这个key)
由于,VOIP应用程序需要一直运行以确保收到来电,所以如果程序通过一个非零的exit code退出,系统将自动重启这个应用程序(这种退出方式可以发生在内存压力大时终止程序运行)。尽管如此,中断应用程序会release所有的sockets,包括那个用于连接voip 服务的socket。因此,当程序运行时,它需要一直从头创建socket。
C、 为了防止断连,voip程序需要定期被唤醒去检查它的服务。为了容易实现这个行为,IOS通过使用(UIApplication setKeepAliveTimeout:handler:)方法建立一个特殊的句柄。你可以在applicationDidEnterBackg
这个keep-alive handler在后台执行,必须尽快的返回参数,它有最多30秒的时间来执行所需的任务,如果这段时间内句柄没有返回,那么系统将终止应用程序。
当你建立了handler之后,确定应用程序所需的最大超时。系统保证会在最大超时之前调用handler,但是这个时间是不确定的,所以你的handler必须在你申明的超时之前做好执行程序的准备。
D、设置audio session,详见Audio Session Programming Guide.
在后台完成有限长度的任务
在被终止之前的任意时间,应用程序会调用beginBackgroundTaskWithE
可以使用task completion去保证那些比较重要但是需要长时间运行的程序不会由于用户切入后台而突然关闭。比如,你可以用这项功能来将用户的信息保存到disk上或者从网络下载一个重要的文件。有两种方式来初始化这样的任务:
1.
2.
1中的两个方法必须是一一对应的,endBackgroundTask:方法告诉系统任务已经完成,程序在此时可以被终止。由于应用程序只有有限的时间去完成后台任务,你必须在超时或系统将要终止这个程序之前调用这个方法。为了避免被终止,你也可以在一个任务开始的时候提供一个expiration handler和endBackgroundTask:方法。(可以查看backgroundTimeRemaining属性来确定还剩多少时间)。
一个程序可以同时提供多个任务,每当你启动一个任务的时候,beginBackgroundTaskWithE
Listing 4-2 Starting a background task at quit time
- (void)applicationDidEnterBackg
{
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithE
[app 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.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
上述例子中,bgTask变量是一个类的成员变量,存储着指向该后台任务标示的指针。
在expriation handler中,可以添加关闭任务所需的代码。尽管如此,加入的代码不能执行太长的时间,当expriation handler被调用的时候,该程序已经非常接近被关闭,所以只有极短的时间来清除状态信息并终止任务。
安排Local Notification的传递
UILocalNotification类提供了一种方法来传递local notifications。和push notifications需要设置remote server不同,local notifications 在程序中安排并在当前的设备上执行。满足如下条件可以使用该能力:
1.
2.
为了安排local notification 的传递,需要创建一个UILocalNotification的实例,并设置它,使用UIApplication类方法来安排它。Local notification对象包含了所要传递的类型(sound,alert,或者badge)和时间何时呈现)。UIApplication类方法提供选项去确定是立即传递还是在指定的时间传递。
Listing 4-3 Scheduling an alarm notification
- (void)scheduleAlarmForDate:(NSDate*)theDate
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotificati
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotificati
// Create a new notification.
UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = @"alarmsound.caf";
alarm.alertBody = @"Time to wake up!";
[app scheduleLocalNotificatio
}
}
Executing Code in the Background
Most applications that enter the background state are moved to the suspended state shortly thereafter. While in this state, the application does not execute any code and may be removed from memory at any time. Applications that provide specific services to the user can request background execution time in order to provide those services.
Important:
Applications linked against iOS SDK 4 and later are automatically assumed to support basic multitasking and to implement the appropriate methods to handle transitions to the background state.
Determining Whether Multitasking Support Is Available
The ability to execute code in the background is not supported on all iOS-based devices. Even devices running iOS 4 or later may not have the hardware to support multitasking. In those cases, the system reverts to the previously defined behavior for handling applications. Specifically, when an application quits, it is terminated and purged from memory.
Even applications built specifically for iOS 4 should be prepared to handle situations where multitasking is not available. If the presence or absence of multitasking changes the way your application behaves, it can use themultitaskingSupported
UIDevice
Listing 4-1
UIDevice* device = [UIDevice currentDevice]; |
BOOL backgroundSupported = NO; |
if ([device respondsToSelector:@selector(isMultitaskingSupported)]) |
backgroundSupported = device.multitaskingSupported; |
Declaring the Background Tasks You Support
Support for some types of background execution must be declared in advance by the application that uses them. An application declares this support by including the UIBackgroundModes
Info.plist
-
audio
. The application plays audible content to the user while in the background. (This includes streaming audio or video content using AirPlay.) -
location
. The application keeps users informed of their location, even while running in the background. -
voip
. The application provides the ability for the user to make phone calls using an Internet connection.
Each of the preceding values lets the system know that your application should be woken up at appropriate times to respond to relevant events. For example, an application that begins playing music and then moves to the background still needs execution time to fill the audio output buffers. Including the audio
In addition to the preceding keys, iOS provides two other ways to do work in the background:
-
Task completion—Applications can ask the system for extra time to complete a given task.
-
Local notifications—Applications can schedule local notifications to be delivered at a predetermined time.
For more information about how to initiate background tasks from your code, see
Implementing Long-Running Background Tasks
Applications can request permission to run in the background in order to manage specific services for the user. Such applications do not run continuously but are woken up by the system frameworks at appropriate times to perform work related to those services.
Tracking the User’s Location
There are several ways to track the user’s location in the background, some of which do not actually involve running regularly in the background:
-
Applications can register for significant location changes. (Recommended)
The significant-change location service offers a low-power way to receive location data and is highly recommended for applications that do not need high-precision location data. With this service, location updates are generated only when the user’s location changes significantly; thus, it is ideal for social applications or applications that provide the user with noncritical, location-relevant information. If the application is suspended when an update occurs, the system wakes it up in the background to handle the update. If the application starts this service and is then terminated, the system relaunches the application automatically when a new location becomes available. This service is available in iOS 4 and later, only on devices that contain a cellular radio. -
Applications can continue to use the standard location services.
Although not intended for running indefinitely in the background, the standard location services are available in all versions of iOS and provide the usual updates while the application is running, including while running in the background. However, updates stop as soon as the application is suspended or terminated, and new location updates do not cause the application to be woken up or relaunched. This type of service is appropriate when location data is used primarily when the application is in the foreground. -
An application can declare itself as needing continuous background location updates.
An application that needs regular location updates, both in the foreground and background, should add the UIBackgroundModes
key to its Info.plist
file and set the value of this key to an array containing the location
string. This option is intended for applications that provide specific services, such as navigation services, that involve keeping the user informed of his or her location at all times. The presence of the key in the application’s Info.plist
file tells the system that it should allow the application to run as needed in the background.
You are encouraged to use the significant location change service or use the standard services sparingly. Location services require the active use of an iOS device’s onboard radio hardware. Running this hardware continuously can consume a significant amount of power. If your application does not need to provide precise and continuous location information to the user, it is best to use those services that minimize power consumption. Chief among these low-power services is the significant location change service introduced in iOS 4. This service provides periodic location updates and can even wake up a background application, or relaunch a terminated application, to deliver them.
For applications that require more precise location data at regular intervals, such as navigation applications, you need to declare the application as a continuous background application. This option is available for applications that truly need it, but it is the least desirable option because it increases power usage considerably.
For information about how to use each of the location services in your application, see
Playing Background Audio
Applications that play audio can include the UIBackgroundModes
audio
) in their Info.plist
When the audio
Info.plist
You can use any of the system audio frameworks to initiate the playback of background audio, and the process for using those frameworks is unchanged. (For video playback over AirPlay, you must use the Media Player framework to present your video.) Because your application is not suspended while playing media files, callbacks operate normally while your application is in the background. Your application should limit itself to doing only the work necessary to provide data for playback while in the background. For example, a streaming audio application would download any new data from its server and push the current audio samples out for playback. You should not perform any extraneous tasks that are unrelated to playing the content.
Because more than one application may support audio, the system limits which applications can play audio at any given time. The foreground application always has permission to play audio. In addition, one or more background applications may also be allowed to play some audio content depending on the configuration of their audio session object. Applications should always configure their audio session object appropriately and work carefully with the system frameworks to handle interruptions and other types of audio-related notifications. For information on how to configure your application’s audio session properly for background execution, see
Implementing a VoIP Application
A
To configure a VoIP application, you must do the following:
-
Add the
UIBackgroundModes
key to your application’s Info.plist
file. Set the value of this key to an array that includes the voip
string. -
Configure one of the application’s sockets for VoIP usage.
-
Before moving to the background, call the
setKeepAliveTimeout:handler:
method to install a handler to be executed periodically. Your application can use this handler to maintain its service connection. -
Configure your audio session to handle transitions to and from active use.
Including the voip
UIBackgroundModes
Most VoIP applications also need to be configured as background audio applications to deliver audio while in the background. Therefore, you should include both the audio
voip
UIBackgroundModes
UIBackgroundModes
Configuring Sockets for VoIP Usage
In order for your application to maintain a persistent connection while it is in the background, you must tag your application’s main communication socket specifically for VoIP usage. Tagging this socket tells the system that it should take over management of the socket when your application is suspended. The handoff itself is totally transparent to your application. And when new data arrives on the socket, the system wakes up the application and returns control of the socket so that the application can process the incoming data.
You need to tag only the socket you use for communicating with your VoIP service. This is the socket you use to receive incoming calls or other data relevant to maintaining your VoIP service connection. Upon receipt of incoming data, the handler for this socket needs to decide what to do. For an incoming call, you likely want to post a local notification to alert the user to the call. For other noncritical data, though, you might just process the data quietly and allow the system to put your application back into the suspended state.
In iOS, most sockets are managed using streams or other high-level constructs. To configure a socket for VoIP usage, the only thing you have to do beyond the normal configuration is add a special key that tags the interface as being associated with a VoIP service.
Interface | Configuration |
---|---|
For Cocoa streams, use the | |
When using the URL loading system, use the | |
For Core Foundation streams, use the |
Note:
Because VoIP applications need to stay running in order to receive incoming calls, the system automatically relaunches the application if it exits with a nonzero exit code. (This type of exit could happen in cases where there is memory pressure and your application is terminated as a result.) However, terminating the application also releases all of its sockets, including the one used to maintain the VoIP service connection. Therefore, when the application is launched, it always needs to create its sockets from scratch.
For more information about configuring Cocoa stream objects, see
Installing a Keep-Alive Handler
To prevent the loss of its connection, a VoIP application typically needs to wake up periodically and check in with its server. To facilitate this behavior, iOS lets you install a special handler using the setKeepAliveTimeout:handler:
method of UIApplication
. You typically install this handler in the applicationDidEnterBackg
Your keep-alive handler executes in the background and should return as quickly as possible. Handlers are given a maximum of 30 seconds to perform any needed tasks and return. If a handler has not returned after 30 seconds, the system terminates the application.
When installing your handler, specify the largest timeout value that is practical for your application’s needs. The minimum allowable interval for running your handler is 600 seconds and attempting to install a handler with a smaller timeout value will fail. Although the system promises to call your handler block before the timeout value expires, it does not guarantee the exact call time. To improve battery life, the system typically groups the execution of your handler with other periodic system tasks, thereby processing all tasks in one quick burst. As a result, your handler code must be prepared to run earlier than the actual timeout period you specified.
Configuring Your Application’s Audio Session
As with any background audio application, the audio session for a VoIP application must be configured properly to ensure the application works smoothly with other audio-based applications. Because audio playback and recording for a VoIP application are not used all the time, it is especially important that you create and configure your application’s audio session object only when it is needed. For example, you would create it to notify the user of an incoming call or while the user was actually on a call. As soon as the call ends, you would then release the audio session and give other audio applications the opportunity to play their audio.
For information about how to configure and manage an audio session for a VoIP application, see
Completing a Finite-Length Task in the Background
Any time before it is suspended, an application can call the beginBackgroundTaskWithE
backgroundTimeRemaining
UIApplication
You can use task completion to ensure that important but potentially long-running operations do not end abruptly when the user leaves the application. For example, you might use this technique to save user data to disk or finish downloading an important file from a network server. There are a couple of design patterns you can use to initiate such tasks:
-
Wrap any long-running critical tasks with
beginBackgroundTaskWithE
xpirationHandler: and endBackgroundTask:
calls. This protects those tasks in situations where your application is suddenly moved to the background. -
Wait for your application delegate’s
applicationDidEnterBackg
round: method to be called and start one or more tasks then.
All calls to the beginBackgroundTaskWithE
endBackgroundTask:
endBackgroundTask:
endBackgroundTask:
backgroundTimeRemaining
An application can have any number of tasks running at the same time. Each time you start a task, the beginBackgroundTaskWithE
endBackgroundTask:
Listing 4-2 applicationDidEnterBackg
bgTask
Listing 4-2
- (void)applicationDidEnterBackg |
{ |
UIApplication* app = [UIApplication sharedApplication]; |
|
bgTask = [app beginBackgroundTaskWithE |
[app 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. |
|
[app endBackgroundTask:bgTask]; |
bgTask = UIBackgroundTaskInvalid; |
}); |
} |
In your own expiration handlers, you can include additional code needed to close out your task. However, any code you include must not take too long to execute. By the time your expiration handler is called, your application is already very close to its time limit. For this reason, perform only minimal cleanup of your state information and end the task.
Scheduling the Delivery of Local Notifications
The UILocalNotification
-
A time-based application can ask the system to post an alert at a specific time in the future. For example, an alarm clock application would use this alert to implement alarms.
-
An application running in the background can post a local notification to get the user’s attention.
To schedule the delivery of a local notification, create an instance of the UILocalNotification
UIApplication
UIApplication
Listing 4-3 application:didReceiveLocalNotificat
Listing 4-3
- (void)scheduleAlarmForDate:(NSDate*)theDate |
{ |
UIApplication* app = [UIApplication sharedApplication]; |
NSArray* oldNotifications = [app scheduledLocalNotificati |
|
// Clear out the old notification before scheduling a new one. |
if ([oldNotifications count] > 0) |
[app cancelAllLocalNotificati |
|
// Create a new notification. |
UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease]; |
if (alarm) |
{ |
alarm.fireDate = theDate; |
alarm.timeZone = [NSTimeZone defaultTimeZone]; |
alarm.repeatInterval = 0; |
alarm.soundName = @"alarmsound.caf"; |
alarm.alertBody = @"Time to wake up!"; |
|
[app scheduleLocalNotificatio |
} |
} |
Sound files used with local notifications have the same requirements as those used for push notifications. Custom sound files must be located inside your application’s main bundle and support one of the following formats: Linear PCM, MA4, µ-Law, or a-Law. You can also specify the sound name default
You can cancel scheduled notifications or get a list of notifications using the methods of the UIApplication