ios后台运行
转自http://blog.csdn.net/diyagoanyhacker/article/details/7071055
文一
从苹果文档中得知,一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后台运行一小段时间。
官方文档:
通过查看官方文档,我们了解到,其后台运行机制,允许三种服务在后台长时间运行,分别是
1. 位置服务
2. 音乐播放
3. VoIP (Voice over Internet Protocol)简而言之就是将模拟信号(Voice)数字化,以数据封包(Data Packet)
的形式在IP网络(IP Network)上做实时传递。例如:网络电话Skype
中文的好文章
http://www.devdiv.com/thread-47004-1-1.html
http://www.cnblogs.com/haipingwu/archive/2011/03/18/1987962.html
iOS4 请求更多后台时间
http://blog.csdn.net/zhangao0086/article/details/6739266
文二
在IOS后台执行是本文要介绍的内容,大多数应用程序进入后台状态不久后转入暂停状态。在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除。应用程序提供特定的服务,用户可以请求后台执行时间,以提供这些服务。
判断是否支持多线程
- 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 传递
文三
如何让程序后台播放音乐
http://developer.apple.com/library/ios/#qa/qa1668/_index.html
文四
如果你的应用程序需要后台运行,可以使用以下方法:
1。应用程序可以请求一个有限的时间内完成一些重要任务。
2。应用程序可以声明为支持特定服务需要定期后台执行时间。
3。应用程序可以使用本地生成用户在指定的时间的警报,应用程序正在运行与否的通知。
原文地址:http://blog.csdn.net/diyagoanyhacker/article/details/7071055
作者:禚来强
声明:此文一部分来自网络,一部分来自官方文档(翻译),还有一部分是作者的总结
文五
后台运行被第一次提到
http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html#//apple_ref/doc/uid/TP40009559-SW1
文六
后台运行官方文档
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW3
在IOS后台执行是本文要介绍的内容,大多数应用程序进入后台状态不久后转入暂停状态。在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除。应用程序提供特定的服务,用户可以请求后台执行时间,以提供这些服务。
判断是否支持多线程
- 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程序需要稳定的网络去连接和它相关的服务,这样它才能接到来电和其他相关的数据。系统允许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: 方法添加
- NSStreamNetworkServiceType
- 属性给
- stream.
- 改属性的值设为
- NSStreamNetworkServiceTypeVoIP.
- 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
- NSURLNetworkServiceTypeVoIP.
CFReadStreamRef和CFWriteStreamRef
- For Core Foundation streams, use the CFReadStreamSetProperty or
- CFWriteStreamSetProperty function to add the kCFStreamNetwork-
- ServiceType property to the stream. The value for this property should be
- set to kCFStreamNetworkServiceTypeVoIP.
(注意:当设置socket的时候,你需要在你的主信号通道中设置合适的service type key。当设置声道时,不需要设置这个key)
由于,VOIP应用程序需要一直运行以确保收到来电,所以如果程序通过一个非零的exit code退出,系统将自动重启这个应用程序(这种退出方式可以发生在内存压力大时终止程序运行)。尽管如此,中断应用程序会release所有的sockets,包括那个用于连接voip 服务的socket。因此,当程序运行时,它需要一直从头创建socket。
C、 为了防止断连,voip程序需要定期被唤醒去检查它的服务。为了容易实现这个行为,IOS通过使用(UIApplication setKeepAliveTimeout:handler:)方法建立一个特殊的句柄。你可以在applicationDidEnterBackground方法中建立该句柄。一旦建立,系统至少会在超时之前调用该句柄一次,来唤醒你的应用程序。
这个keep-alive handler在后台执行,必须尽快的返回参数,它有最多30秒的时间来执行所需的任务,如果这段时间内句柄没有返回,那么系统将终止应用程序。
当你建立了handler之后,确定应用程序所需的最大超时。系统保证会在最大超时之前调用handler,但是这个时间是不确定的,所以你的handler必须在你申明的超时之前做好执行程序的准备。
D、设置audio session,详见Audio Session Programming Guide.
在后台完成有限长度的任务
在被终止之前的任意时间,应用程序会调用beginBackgroundTaskWithExpirationHandler:方法让系统给出额外的时间来完成一些需要在后台长时间执行的任务。(UIApplication的backgroundTimeRemaining属性包含程序运行的总时间)
可以使用task completion去保证那些比较重要但是需要长时间运行的程序不会由于用户切入后台而突然关闭。比如,你可以用这项功能来将用户的信息保存到disk上或者从网络下载一个重要的文件。有两种方式来初始化这样的任务:
1、将长时间运行的重要任务用beginBackgroundTaskWithExpirationHandler:和endBackgroundTask:包装。这样就在程序突然切入后台的时候保护了这些任务不被中断。
2、当你的应用程序委托applicationDidEnterBackground:方法被调用时再启动任务
中的两个方法必须是一一对应的,endBackgroundTask:方法告诉系统任务已经完成,程序在此时可以被终止。由于应用程序只有有限的时间去完成后台任务,你必须在超时或系统将要终止这个程序之前调用这个方法。为了避免被终止,你也可以在一个任务开始的时候提供一个expiration handler和endBackgroundTask:方法。(可以查看backgroundTimeRemaining属性来确定还剩多少时间)。
一个程序可以同时提供多个任务,每当你启动一个任务的时候,beginBackgroundTaskWithExpirationHandler:方法将返回一个独一无二的handler去识别这个任务。你必须在endBackgroundTask:方法中传递相同的handler来终止该任务。
- Listing 4-2 Starting a background task at quit time
- - (void)applicationDidEnterBackground:(UIApplication *)application
- {
- UIApplication* app = [UIApplication sharedApplication];
- bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
- [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、一个基于时间的程序,可以在将来特定的时间让程序post 一个alert,比如闹钟
2、一个在后台运行的程序,post 一个local notification去引起用户的注意
为了安排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 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] autorelease];
- 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];
- }
- }
(可以最多包含128个 local notifications active at any given time, any of which can be configured to repeat at a specified interval.)如果在调用该notification的时候,程序已经处于前台,那么application:didReceiveLocalNotification:方法将取而代之。
小结:关于详解在IOS后台执行的内容介绍完了,希望本文对你有所帮助!
文七
iOS不是真正的多任务系统,在用户按下Home按钮后,所有应用程序都会进入后台状态,并且大部分都会迅速进入暂停状态,应用程序的所有工作内存都在RAM中,在暂停时它完全不执行。因此,切换回这样的应用程序非常快。但是如果系统需要更多的内存给当前处于活动状态的应用程序,就有可能终结暂停状态的应用程序,它们的内存也将被释放。
一方面,应用程序在进入后台状态时,需要释放一些资源,使自身的暂停快照更小,从而减少从RAM中清除的风险,另一方面,为了避免被终结而丢失用户的数据,需要在用户离开时保存他们的进度信息,这些工作,需要在5秒钟内完成,不然会被系统认定有异常被强制退出。可能通过接收应用程序发送的通知(UIApplicationDidEnterBackgroundNotification)来触发处理,如果在处理代码中加上下面这条语句则必然会导致异常退出:
- [NSThread sleepForTimeInterval:10];
可以通过一种方法来请求更多后台时间来避免此问题。假设接收通知而触发的处理方法是applicationDidEnterBackground:
- -(void)applicationDidEnterBackground{
- NSLog(@"%@",NSStringFromSelector(_cmd));
- //得到当前应用程序的UIApplication对象
- UIApplication *app = [UIApplication sharedApplication];
- //一个后台任务标识符
- UIBackgroundTaskIdentifier taskID;
- taskID = [app beginBackgroundTaskWithExpirationHandler:^{
- //如果系统觉得我们还是运行了太久,将执行这个程序块,并停止运行应用程序
- [app endBackgroundTask:taskID];
- }];
- //UIBackgroundTaskInvalid表示系统没有为我们提供额外的时候
- if (taskID == UIBackgroundTaskInvalid) {
- NSLog(@"Failed to start background task!");
- return;
- }
- NSLog(@"Starting background task with %f seconds remaining", app.backgroundTimeRemaining);
- [NSThread sleepForTimeInterval:10];
- NSLog(@"Finishing background task with %f seconds remaining",app.backgroundTimeRemaining);
- //告诉系统我们完成了
- [app endBackgroundTask:taskID];
- }
文八:
转自http://www.cnblogs.com/zzltjnh/archive/2013/05/15/3080058.html
最近再做一个类似于“驾考宝典”的iOS应用,当然作为考试计时的功能肯定不会少,开发期间也是遇到各种各样的小问题,本文所讲为其中之一:iOS程序进入后台后十分钟之内就会被系统kill掉,怎么解决呢?我想要程序进入后台后仍然运行计时功能,否则就无法达到考试的目的,之后在网上查阅了相关资料最后终于找到答案,其精髓就是:利用苹果给出的三种类型的程序可以保持在后台运行:音频播放类,位置更新类,另外一个记不太清楚了,我利用了苹果给出的音频播放类的这个“特权”来满足我程序上的要求,详细步骤如下:
1、步骤一:在Info.plist中,添加"Required background modes"键,value为:App plays audio
步骤二:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. NSError *setCategoryErr = nil; NSError *activationErr = nil; [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryErr]; [[AVAudioSession sharedInstance] setActive: YES error: &activationErr]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
步骤三:将以下代码添加到appDelegate文件中的- (void)applicationDidEnterBackground:(UIApplication *)application函数,也可添加到在具体类中注册的应用进入后台后的通知方法
- (void)applicationDidEnterBackground:(UIApplication *)application{ UIApplication* app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier bgTask; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ if (bgTask != UIBackgroundTaskInvalid) { bgTask = UIBackgroundTaskInvalid; } }); }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_main_queue(), ^{ if (bgTask != UIBackgroundTaskInvalid) { bgTask = UIBackgroundTaskInvalid; } }); }); }
完成以上步骤你会发现,程序进入后台后仍可运行定时器!
文九
1,首先iOS4.0以后,app有background状态的,这个状态一般是系统给应用预留的,让其可以在进入suspend(挂起)状态之前把未完成的任务完成,在app代理函数appDidEnterBackground中有5s的时间给你,如果5s不够,可以使用
UIBackgroundTaskIdentifier bgTask=UIBackgroundTaskInvalid;
if (bgTask==UIBackgroundTaskInvalid){
bgTask=[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
//后台任务到期时执行的代码,一般就是结束后台任务,并置bgTask为Invalid
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask=UIBackgroundTaskInvalid;
}];
//只需要调用这一句代码即可,这样系统就会给你10分钟免费的后台时间让你执行代码。
}
但是后台任务只有10分钟,如果你想让程序一直运行下去怎么办?
2,在Info.plist文件中指定或添加UIBackgroundModes键(直接输入后系统会将该键变为Required background modes),其类型为一个array,包含子项为字符串,可以为voip、location、voip(注意这些值在你输入后系统会自动变更为其它的值,例如你输入location,系统会将其变为App registers for location updates,当然你也可以直接选择系统提供的项,只是注意这里写的值和系统给的值字面上是不一样的)
3、所以你如果想一直在后台运行代码,我最初的想法是通过在后台使用一个[locationManager startUpdateLocation],然后其代理函数什么都不用做,其作用只是为了维持应用为后台状态,或把应用从suspend状态变回background状态。但是这样状态栏会一直显示定位的标记,而且需要用户允许你定位才可以。而且最重要的是应该很费电吧。
注意:使用[locationManager startMonitoringSignificantLocationChanges],这个定位服务可以把程序从未运行状态拉回后台状态,而且不需要指定UIBackgroundModes键。但是不能让后台任务运行超过10分钟,即使指定了UIBackgroundModes建为location,后台任务也不会超过10分钟
也就是说[locationManager startUpdateLocation]和[locationManager startMonitoringSignificantLocationChanges]的区别是一个能让后台任务一直运行,一个能把未运行的App拉回background状态。
可以两个都用,如果你的应用被退出了,那么如果用户移动了一段显著的位置后,App会被自动加载回background状态。
4、但是一直看状态栏显示一个定位的标志很不爽,所以决定试一下VoIP,按照官方说法,voip的程序会开机自动加载到后台(经实验,这个是真的),会在App意外退出(退出值不为0)后自动加载到后台(这个不会实验,代码exit(1),和手动结束程序都不能继续唤醒App,也许系统因为内存吃紧,将吃关闭的时候才可以恢复吧)。不过能在后台运行就差不多了,不要求那么多了。
1)首先配置UIBackgroundModes值加入voip,且增加了voip之后,即使不再指定audio,也能在后台播放音乐,但是官方建议还是加上audio。
2)配置socket:这里我主要是借用voip,而不是真正实现voip,所以只是简单的用NSURLRequest类,创建一个NSMutableURLRequest实例,并设置其networkServiceType属性为NSURLNetworkServiceTypeVoIP。
3)在App代理函数applicationDidEnterBackground:中使用[application setKeepAliveTimeout:handler:]来为应用添加一个Keep-Alive Handler。一旦安装了Handler,系统会在timeout 之前至少调用一次handler,handler有10s的运行时间,否则系统会挂起应用。
timeout值要小一些,如果你打算15分钟唤醒一次,那么你就设置timeout小于15分钟,例如10分钟、12分钟等。因为系统虽然承诺调用handler,但是它会把handler的代码和其它系统周期性的任务放在一起执行,可能会延误一点时间。
注意:timout值不能小于600s
下面是测试及结论:
测试1-1:不指定UIBackgroundModes为location,启动startMonitoringSignificantLocationChanges
结果: 后台任务只能维持10分钟
测试1-2:指定UIBackgroundModes为location,启动startMonitoringSignificantLocationChanges
结果: 后台任务还是只能维持10分钟
结论1:startMonitoringSignificantLocationChanges不能让后台任务一直运行,即使指定了UIBackgroundModes为location,但是他能让App从未运行状态转到后台状态
测试2-1:在指定UIBackgroundModes为location时,不启动标准startUpdateLocation
结果:后台任务只能维持10分钟。
测试2-2:在指定UIBackgroundModes为location时,启动标准startUpdateLocation,在代理函数中将其停止
结果:后台任务还是只能维持10分钟,但是状态栏中定位的小标记不会消失。。
测试2-3:在指定UIBackgroundModes为location时,启动标准startUpdateLocation,然后不停止它
结果:后台任务可以无限跑下去。。。
结论2:即使指定了UIBackgroundModes为location,也需要 locationManager startUpdateLocation,并且不能停止才能让 App一直运行下去。
测试3-1:指定UIBackgroundModes为voip时,创建一个MSMutableURLRequest并设置属性,如下:
self.myRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
self.myRequest.networkServiceType=NSURLNetworkServiceTypeVoIP;
然后在applicationDidEnterBackground:方法中设置一个handler 块,间隔10分钟多一点
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[application setKeepAliveTimeout:600.1f handler:^{ [self setMyBgTask];}]; //此处注意timeout值不能少于600,并在Handler中加入启动后台任务的代码,因为超过10分钟,后台任务肯定已经停止了
[self setMyBgTask];
}
结论:voip可以让app开机自动进入到后台状态,可以让app在后台运行,至于能不能让app从未运行状态到后台状态,还未确定。
================
另:转自其它文章
1、检查设备是否支持多任务
Apple出于性能的考虑,并不是所有的iOS设备升级到iOS4以后都支持多任务,比如iPhone 3G。如果你的应用在没有多任务特性时会出问题,为了保持应用的健壮性,你应该对此进行判断并处理。你可以通过调用UIDevice对象的multitaskingSupported属性来获取当前设备是否支持多任务。
if(![UIDevice currentDevice].multitaskingSupported){
//不支持多任务时应做的处理
}