iOS的后台运行和多任务处理

好久之前整理了一篇iOS运行状态的文章,其中略微提到了应用程序在后台时的情况。本文将本人对iOS的后台运行和多任务处理支持的个人理解和实践做一个稍微详细一点的整理。网上关于iOS后台运行和多任务支持的文章不少,但其中很多都是转来转去甚至是抄来抄去,本篇虽不能面面俱到,但可以说是本人结合苹果官方的几篇文档理解后的一个原创。

0. iOS对后台支持的历史背景

根据苹果目前的文档来看,大致可以将iOS从最开始到iOS7.0后的版本对后台任务支持分为三大阶段,分别是:

  • iOS4.0以前。据说这个阶段iOS是完全没有后台的概念的,只有一个不受前后台影响的推送功能,只要在iPhone上按下了圆圆的Home键,应用直接被关掉。这个阶段我只能是根据老苹果用户的文章来推断了,因为我本人近距离接触iOS也是在4.0之后的时候。
  • iOS4.0以后,7.0之前。苹果现存的后台运行和多任务支持的基本上都是4.0开始的,可以说这是一个重要的分界点。这一阶段的特点是应用有后台的概念,按Home键之后应用不退出,但冻结,网络上有一个名称叫做“墓碑式”
  • iOS7.0之后。新增了机种后台运行模式,增加了智能调度。

既然现在大多数的情况都是4.0之后的特征,下文我们就详细来看。

1.  “禳星续命”

《三国演义》第一百零三章标题为“上方谷司马受困,五丈原诸葛禳星”,对三国有点了解的人都知道诸葛亮禳星续命的经典故事。大意是讲诸葛亮在五丈原和敌军僵持,但知道自己命不久矣,为了“酬三顾”希望能够让自己再多活些时日以胜此仗,至于结局这里就不用说了。

那么当iOS(4.0之后)的应用状态将要从Active经由Inactive退到Background的时候,能不能争取到一些执行时间来完成“墓碑式”冻结前最后的任务呢?苹果给了这个机会。

在前面一篇文章“iOS应用程序的状态及其切换(生命周期)”中整理了生命周期相关的方法,在程序进入后台的时候,方法:

- (void)applicationDidEnterBackground:(UIApplication *)application

会被调用从而开始执行后台运行的程序,官方文档中要求此方法需在5秒内结束。

按文档给出的示例,可以给出如下调用:

- (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;
    });
}

这种方式是苹果推荐的方式,比较优雅。我个人用iOS7的真机调试,默认情况下会在后台跑3分钟,然后停掉。

大家如果感兴趣也可以尝试在applicationDidEnterBackground方法中使用主线程跑一个足够长的任务,看看会怎样。

2. 真后台和服务

iOS从诞生到现在对应用的后台运行一直有所限制,了解苹果产品的朋友应该都明白,这正是苹果为了提高用户体验而做的取舍,为了手机的资源更合理的利用,而不是被后台运行的“卡死”或者手机电量无辜消耗。

既然传说中4.0之前的时代都有推送,那么4.0之后肯定也是要支持的。消息推送可是把客户端和服务器紧密结合起来满足商业需求的重要利器。除了消息推送通知,iOS也有对应的本地通知。

实际上,除了消息以外,苹果的iOS对特定的服务也是支持真后台运行的。主要包括:

  • 音乐播放和录制,比如你打开虾米播放器再退到后台,音乐也还是播放着的
  • 定位服务,iOS的定位服务分为显著位置变化检测和高精确度的定位,后者是支持后台定位跟踪的
  • VoIP
  • 蓝牙及外部设备通信

当然,真后台的服务也不止这些,更详细的可以参看这里:

Background Execution

3. iOS7.0的新东西

iOS7版本,苹果在后台运行服务和多任务处理这块又增加了一些新东西。按照苹果文档所述,分为三种方式:

  • 退到后台时,短时间延续之前执行的任务
  • 在前台时初始化,但尚未完成的下载任务
  • 真正意义的后台运行服务(新增了几种服务支持)

第一点,上面“禳星续命”已经提过,下面主要说下第二点和第三点。

在iOS7中,新增了NSURLSession这个类,可以通过NSURLSessionConfiguration这个类的类方法得到后台的URLSession配置,以此初始化NSURLSession对象可以在后台仍然保持运行。同时,要在ApplicationDelegate中实现(application:handleEventsForBackgroundURLSession:completionHandler: )方法,以保证特定事件的处理。根据NSURLSessionConfiguration对象的属性配置,在某些情况下,会从后台唤起App。

iOS7以后,后台运行的服务也新增了2种,分别是:

  • fetch
  • remote-notification

只要你在App的后台运行模式里选择了fetch,系统便会按照自己的逻辑“智能”地调用ApplicaitonDelegate中的回调方法,实现上传或者下载任务,完成时开发者负责告知系统,系统核算任务进行所消耗的资源,“智能”地调整调用频率。

“remote-notification”直接翻译过来就是“远端通知”,或者更直白的“消息推送”。但这与传统的消息推送略有不同,如果勾选此项,则ApplicationDelegate的回调会在App仍处于后台的情况下得到调用,这在iOS7以前是不可能的(以前得到inActive的state也要app恢复前台运行才有可能)。并且在delegate的回调中,可以考虑实现为展现通知所必要的下载准备工作。需要注意的有2点:

  • 想要触发回调,要求消息本身包含content-available
  • 新的ApplicationDelegate回调方法会覆盖老的

关于iOS后台服务和多任务处理的内容,简要整理到此。

更多请参见:What’s New in iOS7

此条目发表在 iOS, iOS开发基础 分类目录,贴了 , , , , , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>