iOS7中的多任务II
【推送唤醒(Remote Notifications)】
在iOS6和之前,推送的类型是很单一的,无非就是显示标题内容,指定声音等。用户通过解锁进入你的应用后,appDelegate中通过推送打开应用的回调将被调用,然后你再获取数据,进行显示。这和没有后台获取时的打开应用后再获取数据刷新的问题是一样的。
在iOS7中这个行为发生了一些改变,我们有机会使设备在接收到远端推送后让系统唤醒设备和我们的后台应用,并先执行一段代码来准备数据和UI,然后再提示用户有推送。这时用户如果解锁设备进入应用后将不会再有任何加载过程,新的内容将直接得到呈现。
1、启用推送唤醒。
更改Info.plist,在UIBackgroundModes
下加入remote-notification
即可开启,当然同样的更简单直接的办法是使用Capabilities。
2、更改推送的payload。
在iOS7中,如果想要使用推送来唤醒应用运行代码的话,需要在payload中加入content-available
,并设置为1。
1 aps { 2 content-available: 1 3 alert: {...} 4 }
3、实现推送唤醒代码并通知系统。
在appDelegate中实现?-application:didReceiveRemoteNotification:fetchCompletionHandle:
。这部分内容后台获取部分完全一样。
Apple将限制此类推送的频率,当频率超过一定限制后,带有content-available标志的推送将会被阻塞,以保证用户设备不被频繁唤醒。按照Apple的说法,这个频率在一小时内个位数次的推送的话不会有太大问题。
【后台传输(?Background Transfer Service)】
iOS7引入了后台传输的相关方式,用来保证应用退出后数据下载或者上传能继续进行。这种传输是由iOS系统进行管理的,没有时间限制,也不要求应用运行在前台。
想要实现后台传输,就必须使用iOS7的新的网络连接的类,NSURLSession。这是iOS7中引入用以替代陈旧的NSURLConnection的类。
1、创建NSURLSession。
1 - (NSURLSession *)backgroundSession 2 { 3 //Use dispatch_once_t to create only one background session. If you want more than one session, do with different identifier 4 static NSURLSession *session = nil; 5 static dispatch_once_t onceToken; 6 dispatch_once(&onceToken, ^{ 7 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.yourcompany.appId.BackgroundSession"]; 8 session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; 9 }); 10 return session; 11 }
2、加入对应的传输用的NSURLSessionTask,并启动下载。
1 //@property (nonatomic) NSURLSession *session; 2 //@property (nonatomic) NSURLSessionDownloadTask *downloadTask; 3 4 - (NSURLSession *)backgroundSession 5 { 6 //... 7 } 8 9 - (void) beginDownload 10 { 11 NSURL *downloadURL = [NSURL URLWithString:DownloadURLString]; 12 NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL]; 13 self.session = [self backgroundSession]; 14 self.downloadTask = [self.session downloadTaskWithRequest:request]; 15 [self.downloadTask resume]; 16 }
3、最后一步是在appDelegate中实现-application:handleEventsForBackgroundURLSession:completionHandler:
1 //AppDelegate.m 2 - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier 3 completionHandler:(void (^)())completionHandler 4 { 5 //Check if all transfers are done, and update UI 6 //Then tell system background transfer over, so it can take new snapshot to show in App Switcher 7 completionHandler(); 8 9 //You can also pop up a local notification to remind the user 10 //... 11 }
一旦后台传输的状态发生变化(包括正常结束和失败)的时候,应用将被唤醒并运行appDelegate中的回调,接下来NSURLSessionTask的委托方法将在后台被调用。虽然上面的例子中直接在appDelegate中call了completionHandler,但是实际上更好的选择是在appDelegate中暂时持有completionHandler,然后在NSURLSessionTask的delegate方法中检查是否确实完成了传输并更新UI后,再调用completionHandler。另外,你的应用到现在为止只是在后台运行,想要提醒用户传输完成的话,也许你还需要在这个时候发送一个本地推送(记住在这个时候你的应用是可以执行代码的,虽然是在后台),这样用户可以注意到你的应用的变化并回到应用,并开始已经准备好数据和界面。
后台传输只会通过wifi来进行。