iOS系统后台运行机制研究

20140410_103412_979.png

众所周知,iOS操作系统上的App,不仅仅是外形美,同时其也是以流畅著称,可以说是极端的流畅。在流畅的外表下,是操作系统对于程序的调度、前后台的切换、内存的管理都达到了极致。

在日常的iOS开发中,不免会遇到需要App在被切到后台之后,仍然需要运行一个进程完成某些特殊的操作,一般后台运行进程作用有以下几类:

  • 后台更新数据、同步刷新UI
  • 与服务端通信,发送心跳,如“XMPP”类App
  • 获取用户地理信息数据(GPS),如新“高德地图”
  • 多媒体App用来继续播放音乐,如“酷狗音乐”
  • 网络电话类App(VoIP)

要完成上述操作,有以下集中解决方案,每种方案各有优劣,适用于不同情况:

一、VoIP

优势:

  • 永远不会被后台进程强杀
  • 实现起来简单

劣势:

  • 只能限定于VoIP类App使用。如无这VoIP功能,如果将App上传到AppStore,则会被拒绝。(虽然看起来没有问题,但是苹果就是这么“吹毛求疵”)

听名字就知道,这个方案是Apple专门为VoIP类App量身定制的。如果你的App并没有VoIP相关功能,在提交AppStore时会被拒绝,但是如果你只是企业内部分发,并不提交AppStore审核的话,就没有啥问题了。使用方法如下:

步骤一、在XCode中为你的Ap工程打开Background Modles,并勾选Voiceover IP选项,等于告诉iOS操作系统你需要此项功能,系统不能在后台强制杀掉我的进程,因为我要在后台进行一些操作。

同时,也可以在工程的plist文件中加入如下选项:

Key:Required background modes

Value:App provides Voice over IP services

步骤二、在需要后台运行的地方执行操作

  1. [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{
  2.    //干活
  3. }];

这个函数会以设定的时间间隔被调用,不仅仅在后台,App在前台时候,这个函数一样能够被调用。所以可以把它当作一个横跨前后台的NSTimer来使用。

注意:

1、间隔时长必须大于600s,适合和服务器保持通讯,保证用户登录状态。

2、复活后,执行时间只有10s,之后又继续挂起。

3、 使用clearKeepAliveTimeout来取消唤醒

4、app必须是能和VoIP功能相关的内容,否则提交App Store会被拒绝。

二、Background fetch方式:

优势:

  • 是官方推荐的后台数据刷新方法
  • 实现比较简单

劣势:

  • 程序被唤醒执行的时间不可控
  • 被唤醒后执行时长有限制

步骤一、设置Background fetch:

步骤二、设置被唤醒最小时间间隔:

[applicationsetMinimumBackgroundFetchInterval:1.0f];

步骤二、需要执行的代码片段

 – (void)application:(UIApplication *)applicationperformFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

注意:

1、代码被执行的时间间隔不可控,操作系统会以科学的方式来调用。

2、设置的时间只是最小时间间隔、操作系统只能保证在最小时间间隔内不会被调用,但是至于是1m还是1h还是多长时间调用,与操作系统当前的状态、用户打开App的频率有关系。

3、被操作系统唤醒后,只能有30s的时间执行你的任务,30s后,将被再次挂起。按说以国内的网络环境来说,基本上30s都能解决问题了。

三、播放空白声音配合“backgroundTask”进行后台运行

优势:

  • 适用于需要进行后台播放音乐,记录地理位置变化等功能的App
  • 可以用来进行一些简单的后台操作(如保活),而不被AppStore的审核人员拒绝,比较隐蔽
  •  唤醒时间间隔可控

劣势:

  • 实现相对于其他几种方案都要麻烦

步骤一:在Info.plist中,添加”Required background modes”键,value为:App plays audio,申明你需要使用后台播放音频的功能。

步骤二:调节音频会话的特性:

  1. – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  2. {
  3.     self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
  4.     // Override point for customization after application launch.
  5.     NSError *setCategoryErr = nil;
  6.     NSError *activationErr  = nil;
  7.     [[AVAudioSession sharedInstance]
  8.      setCategory: AVAudioSessionCategoryPlayback
  9.      error: &setCategoryErr];
  10.     [[AVAudioSession sharedInstance]
  11.      setActiveYES
  12.      error: &activationErr];
  13.     self.window.backgroundColor = [UIColor whiteColor];
  14.     [self.window makeKeyAndVisible];
  15.     return YES;
  16. }
 
步骤三、将以下代码添加到appDelegate文件中的- (void)applicationDidEnterBackground:(UIApplication *)application函数,也可添加到在具体类中注册的应用进入后台后的通知方法
  1. – (void)applicationDidEnterBackground:(UIApplication *)application{
  2.     UIApplication*   app = [UIApplication sharedApplication];
  3.     __block    UIBackgroundTaskIdentifier bgTask;
  4.     bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
  5.         dispatch_async(dispatch_get_main_queue(), ^{
  6.             if (bgTask != UIBackgroundTaskInvalid)
  7.             {
  8.                 bgTask = UIBackgroundTaskInvalid;
  9.             }
  10.         });
  11.     }];
  12.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  13.         dispatch_async(dispatch_get_main_queue(), ^{
  14.             if (bgTask != UIBackgroundTaskInvalid)
  15.             {
  16.                 bgTask = UIBackgroundTaskInvalid;
  17.             }
  18.         });
  19.     });
  20. }

这样,就可以在你需要重复执行的地方,实现一个NSTimer,有了上面的步骤之后,你的NSTimer就能不论前台后台都可以运行了。

注意:

和前三个不一样,前三个解决方案是程序被挂起之后又被唤醒,但是,这个解决方案是程序一直在后台运行,会非常耗内存,需要开发者关注。

四、远程消息推送,激活

优点:

  • 实现简单
  • 唤醒时间可控,由后台控制

缺点:

  • 需要后台编码,跑服务进行App唤醒

步骤一、服务端设置推送的消息中加上“content-available”:

  1. {
  2.      “aps” : {
  3.           “content-available” : 1
  4.      },
  5.      “content-id” : 42
  6. }

步骤二、在接收消息的地方,进行唤醒后需要的操作

五、利用NSURLSession进行background transfer task

这种解决方案详见参考资料:http://www.starming.com/index.php?v=index&view=69