打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
iOS 7 SDK:后台传输服务(Background Transfer Service)
本文主要说说如何使用iOS 7多任务处理中的后台传输服务(Background Transfer Service),并讲述如何创建一个app--当不在前台运行时也能下载文件的app。一旦完成全部下载,还会弹出一个通知信息提醒用户。
后台传输服务最初是由iOS 6引入的,允许app在前台和后台传输文件,但有时间限制。最大的问题是“limited minutes”不允许用户下载或上传比较大的文件。这也是苹果在iOS 7中改进这项功能的原因。
在iOS 7中,该功能发生了以下变化:
iOS系统管理下载和上传内容
当用户关闭app后继续传输内容
没有时间限制
可以随时加入队列(前台和后台)
为了处理认证、错误或者completion事件,app会被唤醒
该app包含一个Progress View
后台传输服务可以用来处理几个不同的有用的任务,比如上传照片或视频,结合后台获取和远程通知,以及保持应用更新(比如购买书籍、TV shows、游戏内容以及其他)。
1.设置工程
要创建该服务,我们需要一个single view,并包含如下属性:
A ViewController
A NavigationController
A Bar Item (to start the Download)
An UIDocumentInterationController (to open the PDF document download)
首先,开始一个新的Xcode iPhone工程。然后创建一个Single View app。接着到Main.Storyboard,在view中添加一些对象。想要添加NavigationController,选中Default View Controller。在Xcode菜单中,选择Editor > Embed In > Navigation Controller。把Bar Item和Progress View拖放至View Controller。一旦完成,View Controller
看起来是以下样式:
然后,添加必要的属性来与我们之前添加的对象进行交互。在ViewController.h添加以下代码:
  1. @property (weak, nonatomic) IBOutlet UIProgressView *progressView; 
  2. - (IBAction)start:(id)sender; 
现在改变ViewController.m的视图。你会看到一个警示,不过不用担心,我们稍后再修复它。回到Main.Storyboard,并链接好相关的属性和动作,这些步骤比较琐碎。
2.NSURLSession
NSURLSession类和相关的类提供了一个可以通过HTTP上传或者下载内容的API,主要用来管理一系列传输任务。我们需要创建三个与这个类直接相关的对象:NSURLSession, NSURLSessionDownloadTask以及 UIDocumentInteractionController。
ViewController.h看起来会是这样:
  1. @property (nonatomic) NSURLSession *session; 
  2. @property (nonatomic) NSURLSessionDownloadTask *downloadTask; 
  3. @property (strong, nonatomic) UIDocumentInteractionController *documentInteractionController; 
另外,你还要声明四个协议:NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate以及UIDocumentInteractionControllerDelegate。
@interface应该是像这样的:
  1. @interface ViewController : UIViewController < NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate,UIDocumentInteractionControllerDelegate> 
 我们将要添加的属性对于session的实例化和操作,以及下载处理非常有好处:可以恢复、暂停、取消或检索状态信息。最后一个属性--UIDocumentInterationController在本文中是用来展示下载的PDF文档。
打开ViewController.m。第一个需要完成的任务是把字符串添加至文件下载的位置。你应该使用一个标准的苹果PDF。
  1. static NSString *DownloadURLString = @"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/ObjC_classic/FoundationObjC.pdf"; 
在viewDidLoad 方法中, 我们实例化并设置session和progress view:
  1. self.session = [self backgroundSession]; 
  2. self.progressView.progress = 0; 
  3. self.progressView.hidden = YES; 
由于你执行了一个并不存在的backgroundSession方法,所以你必须声明它,该方法主要用来产生一个在后台运行的会话。NSURLSessionConfiguration接收的NSString参数是我们创建的会话的ID,对于每个NSURLSession实例,这个ID必须是独一无二的。
完整的方法如下:
  1. - (NSURLSession *)backgroundSession { 
  2.   static NSURLSession *session = nil; 
  3.   static dispatch_once_t onceToken; 
  4.   dispatch_once(&onceToken, ^{ 
  5.     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"]; 
  6.     session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; 
  7.   }); 
  8.   return session; 
 (IBAction)start:(id)sender方法开启了文档下载。你将会初始化一个NSURL和 NSURLRequest,并使用downloadTask属性把请求对象传递至downloadTaskWithRequest方法,完整的方法如下:
  1. - (IBAction)start:(id)sender { 
  2.   if (self.downloadTask) { 
  3.         return; 
  4.     } 
  5.   NSURL *downloadURL = [NSURL URLWithString:DownloadURLString]; 
  6.   NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL]; 
  7.   self.downloadTask = [self.session downloadTaskWithRequest:request]; 
  8.     [self.downloadTask resume]; 
  9.     self.progressView.hidden = NO; 
3.协议
在这一点上,你会注意到3个警示,它们表示应该执行协议方法。NSURLSessionDownloadDelegate协议定义了处理下载任务的方法。想要执行下载,它需要使用三个委托方法,所以添加以下三个方法:
1. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:
(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
2. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL {
3. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite方法主要用来跟踪整个下载进程,同时也相应地更新 progressView。整个方法如下:
  1. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { 
  2.     if (downloadTask == self.downloadTask) { 
  3.         double progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite; 
  4.         NSLog(@"DownloadTask: %@ progress: %lf", downloadTask, progress); 
  5.         dispatch_async(dispatch_get_main_queue(), ^{ 
  6.             self.progressView.progress = progress; 
  7.         }); 
  8.     } 
 4.下载任务
(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL方法处理数据(origin and destination)。它在下载完成后控制文件。简化起见,它通知delegate下载任务已经完成。它包含已经完成的session task和download task,以及文件URL(可以在此找到临时文件)。看起来应该是这样:
  1. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL { 
  2.     NSFileManager *fileManager = [NSFileManager defaultManager]; 
  3.     NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; 
  4.     NSURL *documentsDirectory = [URLs objectAtIndex:0]; 
  5.     NSURL *originalURL = [[downloadTask originalRequest] URL]; 
  6.     NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]]; 
  7.     NSError *errorCopy; 
  8.     // For the purposes of testing, remove any esisting file at the destination. 
  9.     [fileManager removeItemAtURL:destinationURL error:NULL]; 
  10.     BOOL success = [fileManager copyItemAtURL:downloadURL toURL:destinationURL error:&errorCopy]; 
  11.     if (success) { 
  12.         dispatch_async(dispatch_get_main_queue(), ^{ 
  13.             //download finished - open the pdf 
  14.             self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:destinationURL]; 
  15.             // Configure Document Interaction Controller 
  16.             [self.documentInteractionController setDelegate:self]; 
  17.             // Preview PDF 
  18.             [self.documentInteractionController presentPreviewAnimated:YES]; 
  19.             self.progressView.hidden = YES; 
  20.         }); 
  21.     } else { 
  22.         NSLog(@"Error during the copy: %@", [errorCopy localizedDescription]); 
  23.     } 
最后 (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes必须也被声明,但要清楚我们不会进一步使用它。
  1. -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { 
 5.Session Tasks
你几乎完成了这个类,只剩下两个方法: (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error和 - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session.
第一个方法通知delegate任务已经完成了数据传输,你也应该用它来跟踪发生的任何错误。
  1. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 
  2.     if (error == nil) { 
  3.         NSLog(@"Task: %@ completed successfully", task); 
  4.     } else { 
  5.         NSLog(@"Task: %@ completed with error: %@", task, [error localizedDescription]); 
  6.     } 
  7.     double progress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive; 
  8.   dispatch_async(dispatch_get_main_queue(), ^{ 
  9.     self.progressView.progress = progress; 
  10.   }); 
  11.     self.downloadTask = nil; 
最后,你需要添加 (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session方法,它通知delegate所有的session消息列队已经交付。为了加载UILocalNotification,它实例化AppDelegate.你应该使用如下方法:
  1. - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { 
  2.     AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
  3.     if (appDelegate.backgroundSessionCompletionHandler) { 
  4.         void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler; 
  5.         appDelegate.backgroundSessionCompletionHandler = nil; 
  6.         completionHandler(); 
  7.     } 
  8.     NSLog(@"All tasks are finished"); 
 由于你没有把AppDelegate.h移植到你的类中,所以会出现几个错误:
  1. #import "AppDelegate.h" 
把两个对象添加至AppDelegate.h:
  1. @property (strong, nonatomic) UIWindow *window; 
  2. @property (copy) void (^backgroundSessionCompletionHandler)(); 
在AppDelegate.m中,你应该执行delegate方法(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler.它通知delegate--与URL session相关的事件正等待处理,并调用自定义方法(presentNotification)通知用户,在文件加载完毕时。完整的方法如下:
  1. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier 
  2.   completionHandler:(void (^)())completionHandler { 
  3.   self.backgroundSessionCompletionHandler = completionHandler; 
  4.     //add notification 
  5.     [self presentNotification]; 
6.本地通知
presentNotification方法用UILocalNotification类来创建本地通知。它创建一个声音,并使用在通知中使用徽标系统--badge system,完整方法如下:
  1. -(void)presentNotification{ 
  2.     UILocalNotification* localNotification = [[UILocalNotification alloc] init]; 
  3.     localNotification.alertBody = @"Download Complete!"; 
  4.     localNotification.alertAction = @"Background Transfer Download!"; 
  5.     //On sound 
  6.     localNotification.soundName = UILocalNotificationDefaultSoundName; 
  7.     //increase the badge number of application plus 1 
  8.     localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1; 
  9.     [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; 
顺便提下,为了重新计算app icon左上角的counter,你必须在AppDelegate中把下边一行代码添加至 (void)applicationDidBecomeActive:(UIApplication *)application方法。
  1. application.applicationIconBadgeNumber = 0; 
通知应该类似于以下这张图: 
现在运行app并测试后台加载。
总结
最后,你应该理解后台传输服务以及知道如何使用它。

原文:iOS 7 SDK: Background Transfer Service

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
三种方式使得iOS应用能够在后台进行数据更新和下载
使用NSURLSession
WWDC 2013 Session笔记
NSURLSession使用说明及后台工作流程分析
iOS NSURLSession Example
Unity与iOS相互调起、交互
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服