聊一聊iOS后台任务

iOS开发的过程中常常会有按下home键盘,进入后台,但不希望当前任务立即停止的情况,比如保存数据,断开链接,继续下载文件等,接下来就简单聊下iOS的后台任务。

一,后台任务的分类

程序的5个状态和对应的AppDelegate的7个方法

  • Not Running, 未运行
  • Inactive, 非活动
  • Active, 活动
  • Background, 后台
  • Suspend, 挂起

对应的方法分别是:

// 进程启动但还没完成初始化,这个方法是iOS6之后才有的

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

// 进程启动基本完成      

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

// 应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件

- (void)applicationWillResignActive:(UIApplication *)application   

// 应用程序入活动状态,这个刚好跟上面那个方法相反

- (void)applicationDidBecomeActive:(UIApplication *)application    

// 程序被推送到后台,如果要设置后台继续运行,则在这个函数里面设置即可

- (void)applicationDidEnterBackground:(UIApplication *)application     

// 程序从后台将要回到前台

- (void)applicationWillEnterForeground:(UIApplication *)application   

// 程序将要退出

- (void)applicationWillTerminate:(UIApplication *)application   

在介绍iOS应用状态5种最基本的状态时,我们发现前台运行有两种状态,分别是Inactive和Active状态。大多数情况下,Inactive状态只是其它状态之间切换时短暂的停留状态,如前后台应用切换时,Inactive状态会在Active和Background之间短暂出现,比如App Switcher/回到原应用的操作等。

用户在按下home键后,app可做的事情有很多,比如听歌、打电话、下载电影、更新数据、定时任务等,可以大致分为两类,注册任务(耗时长)和非注册任务(耗时较短)。

二,非注册任务的运行

非注册任务一般耗时较短,多用来保存数据或延迟执行某一命令等,通过系统API即可实现。可以先看一段官方实例代码:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
        // 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.
}

beginBackgroundTaskWithName:expirationHandler:方法标识了一个后台任务的开始,并用过超时处理的回调来结束此任务。那么,超时时间具体是多少?可以通过UIApplication的只读属性backgroundTimeRemaining来获取当前后台任务执行的剩余时间,它不是具体的数字(我执行的时间大概160秒),而是iOS根据当前系统环境综合考量后估算出来的。然后执行expirationHandler回调完成一个后台任务的执行周期。

三,注册任务的流程

有些耗时较长的工作,则需要申请专门的权限来保证正常执行而不被挂起,只有少数几种类型被允许这个做。

  • Apps that play audible content to the user while in the background, such as a music player app
  • Apps that record audio content while in the background
  • Apps that keep users informed of their location at all times, such as a navigation app
  • Apps that support Voice over Internet Protocol (VoIP)
  • Apps that need to download and process new content regularly
  • Apps that receive regular updates from external accessories

申请使用以上场景的后台权限需要在Xcode->Capabilities->Background Mode中配置,如下图所示:

勾选所需的模式后,会自动在app的info.plist文件中添加Required background modes一项,包含了所勾选的后台运行模式。如下所示:

<key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>voip</string>
    </array>

以Background Fetch为例,具体说下任务流程。

首先需要在Xcode Capabilities 中开启Background fetch选项,在didFinishLaunchingWithOptions中设置下获取的时间间隔:

[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

如果不对最小后台获取间隔进行设定的话,系统将使用默值UIApplicationBackgroundFetchIntervalNever,也就是永远不进行后台获取。而最小的时间间隔则有系统根据电量、网络状态、用户使用习惯等综合考量后来设定一定的差值,执行fetch任务,具体代码如下:

//File: YourAppDelegate.m
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;

    id fetchViewController = navigationController.topViewController;
    if ([fetchViewController respondsToSelector:@selector(fetchDataResult:)]) {
        [fetchViewController fetchDataResult:^(NSError *error, NSArray *results){
            if (!error) {
                if (results.count != 0) {
                    //Update UI with results.
                    //Tell system all done.
                    completionHandler(UIBackgroundFetchResultNewData);
                } else {
                    completionHandler(UIBackgroundFetchResultNoData);
                }
            } else {
                completionHandler(UIBackgroundFetchResultFailed);
            }
        }];
    } else {
        completionHandler(UIBackgroundFetchResultFailed);
    }
}

与fetch类型的是,后台任务同样可以满足远程通知唤醒app执行某一进程,结束后以本地通知的方式提醒用户,以静默、智能的方式带给用户使用上的绝佳体验,相似的场景还有后台电影、音乐的下载等,在此不多做介绍。

四,后台任务的注意事项

1,关于OpenGL ES

有些基于位置的app需要后台定时更新用户的当前位置,导致未知崩溃。原因就是Location update类型的后台任务在更新位置时,需要重新绘制MKMapView,调用了OpenGL ES,而OpenGL ES必须在程序Inactive以前关闭,不然会crash。如官方文档描述:To summarize, your app needs to call the glFinish function to ensure that all previously submitted commands are drained from the command buffer and are executed by OpenGL ES. After it moves into the background, you must avoid all use of OpenGL ES until it moves back into the foreground.

可以在更新位置之前做一下app状态的检测:

if( (appState != UIApplicationStateBackground) && (appState != UIApplicationStateInactive)) {
     // update location
}
2,关于CAAnimation动画

OpenGL提供了Core Animation的基础,它是底层的C接口,直接和iPhone,iPad的硬件通信,极少地抽象出来的方法。当app进入background模式时,所有基于Core Animation 的动画将自动停止,这是因为动画的渲染需要调用Open GL或者Core Graphics来实现UIKit层的变动,然后在applicationWillEnterForeground的时候重新启动即可。

参考:

http://onevcat.com/2013/08/ios7-background-multitask/

https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,689评论 0 3
  • 自从古老的iOS4以来,当用户点击home建的时候,你可以使你的APP们在内存中处于suspended(挂起)状态...
    木易林1阅读 3,040评论 1 4
  • 首先Apple官方为我们准备了三类后台任务执行的场景: 1.Background Tasks:APP 在前台时启动...
    糊糊涂涂888阅读 5,829评论 2 12
  • 公司:宁波大发化纤有限公司 姓名:陆小燕 期数:六项精进234期学员 组号:利他三组 [日精进打卡第167天] [...
    牛妈牛妈阅读 194评论 0 0
  • 这里的刺激不是疯狂,而是精神上的激励。前一个月下载了一个app,是关于英语听力练习的,初衷也是大学英语四级。很单纯...
    YOO1998阅读 184评论 0 0