Background Fetch

Background Fetch 是 iOS7 带来的非常 Cool 的新特性,开启 Background Fetch 的 App 会被系统在合适的时机执行后台任务的代码。比如这个场景:你每天晚上 10 点会通过自己的 RSS 阅读器 App 来阅读,系统可能会在 10 点之前执行 App 中设定的下载 RSS 最新资源的任务,当你打开 RSS 阅读器 App 的时候就显示出最新的内容。实现 Background Fetch 的步骤也是非常的简单,下面就来看一下。

1、开启 Background Fetch

给一个 App 开启 Background Fetch 非常的简单,可以总结为三个步骤:

#Step 1

进入 Project 设置 -> Capabilities -> 设置 Background Modes 为 ON -> 选中Background Fetch

BG_Fetch01

#Step 2

在 ApplicationDelegate 类的

1
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中,添加下面的代码:

1
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

MinimumBackgroundFetchInterval参数值是时间间隔的数值,系统保证两次 Fetch 的时间间隔不会小于这个值,不能保证每隔这个时间间隔都会调用。这里设置为UIApplicationBackgroundFetchIntervalMinimum,意思是告诉系统,尽可能频繁的调用我们的 Fetch 方法。

#Step 3

开始实现我们的 Fetch 方法,在 ApplicationDelegate 类中加入下面这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
SSViewController *ssVC = (SSViewController*)self.window.rootViewController;
if ([ssVC isKindOfClass:[SSViewController class]]) {
NSLog(@"is SSViewController");
ssVC.indexValue ++;
completionHandler(UIBackgroundFetchResultNewData);
} else {
NSLog(@"is not SSViewController");
completionHandler(UIBackgroundFetchResultFailed);
}

}

这个方法每次系统执行 Background Fetch 时都会被调用,可以在这里下载网络数据等。执行完下载任务之后,需要立即调用completionHandlerblock。文档中提到系统用耗时来估算这次 fetch 的电量消耗和数据消耗,如果耗时比较长,未来可能减少被调用的机会。completionHandlerblock 可以用的参数值有下面三个:

  • UIBackgroundFetchResultNewData 拉取数据 OK
  • UIBackgroundFetchResultNoData 没有新数据
  • UIBackgroundFetchResultFailed 拉取数据失败或者超时

文档中也提到,当这个方法被调用后,App 有 30s 的时间来执行下载操作,然后马上执行completionHandlerblock,就是说最好能把下载任务的耗时限制在 30s 内,超过 30s 的,App 会被系统挂起。

在刚才给出的方法中,为了方便测试只是更新了 ViewController 的一个参数值,这个参数值会直接反应到界面上,方面测试。

有个小细节是假如 Background Fetch 方法更新了 UI 的话,系统会刷新 Home 键切换 App 界面中的缩略图。

2、模拟 Background Fetch

创建了 Background Fetch 后,怎么来方面的模拟和测试呢?有两种方式,一种是在 App 被挂起后,系统执行 Background Fetch,另外一种是 App 没有在运行,被系统唤醒执行 Background Fetch 方法。

# 情况 1

直接运行程序,在 Xcode 的菜单中,选择 "Debug" -> "Simulate Background Fetch",你会发现会先打开 App,然后后台挂起,接着执行 (void)application: performFetchWithCompletionHandler 方法。

BG_Fetch02

# 情况 2

复制(Duplicate)一份当前的 Schema,在新的 Schema 的 Options 下,选中 "Launch due to a background fetch event",运行这个 Schema。

BG_Fetch03

BG_Fetch04

3、Remote Notifications & Background Transfer Service

Background Fetch 适用于定期检查更新数据,如果想从服务端推送一条消息告诉客户端来执行某些操作的话,可以使用 Remote Notifications,它和普通的 Push Notification 很相似,不同的是推送时的 Payload 不太一样以及客户端收到通知之后会执行一个的方法,和 Background Fetch 一样有 30s 的时间来做事情。你看到这里一定有个疑问,如果任务在 30s 内不能完成怎么破?比如下载音视频文件。Background Transfer Service 闪亮出场了,感兴趣的话可以参考 Ref 里的第 3、4 条链接里的内容。

Ref

完鸟,如果有写的不对的地方,欢迎小伙伴们指正,Have fun~