iOS怎么进行后台下载,断点下载

iOS怎么进行后台下载,断点下载

从iOS7以来,苹果阿爸推出NSURLSession后,iOS现在可以实现真正的后台下载。

一个NSURLSession对象可以协调一个或多个NSURLSessionTask对象,并且根据NSURLSessionTask创建的NSURLSessionConfiguration实现不同的功能,使用相同的配置,你也可以创建多组具有相关任务的NSURLSession对象,要利用后台传输服务,你将会使用[NSURLSessionConfiguration backgroundSessionConfiguration]来创建一个会话配置,添加到后台会话的任务在外部进程运行,即使应用程序被挂起,崩溃,或者被杀死,它依然会运行。

下面我们来看看如何使用NSURLSession

下载用到的委托方法

1:AppDelegate委托方法

//在应用处于后台,且后台任务下载完成时回调 - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler;                  

2:NSURLSession委托方法

/* 在任务下载完成、下载失败 * 或者是应用被杀掉后,重新启动应用并创建相关identifier的Session时调用 */ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;  

/* 应用在后台,而且后台所有下载任务完成后,

* 在所有其他NSURLSession和NSURLSessionDownloadTask委托方法执行完后回调,

* 可以在该方法中做下载数据管理和UI刷新  */-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession*)session;

注:最好将handleEventsForBackgroundURLSession中completionHandler保存,在该方法中待所有载数据管理和UI刷新做完后,再调用completionHandler()

NSURLSessionDownloadTask委托方法

/* 下载过程中调用,用于跟踪下载进度

* bytesWritten为单次下载大小

* totalBytesWritten为当当前一共下载大小

* totalBytesExpectedToWrite为文件大小

*/-(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTaskdidWriteData:(int64_t)bytesWrittentotalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;

/* 下载恢复时调用

* 在使用downloadTaskWithResumeData:方法获取到对应NSURLSessionDownloadTask,

* 并该task调用resume的时候调用

  */-(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTaskdidResumeAtOffset:(int64_t)fileOffsetexpectedTotalBytes:(int64_t)expectedTotalBytes;

//下载完成时调用- (void)URLSession:(NSURLSession*)session      downloadTask:(NSURLSessionDownloadTask*)downloadTaskdidFinishDownloadingToURL:(NSURL*)location;

注:在URLSession:downloadTask:didFinishDownloadingToURL方法中,location只是一个磁盘上该文件的临时 URL,只是一个临时文件,需要自己使用NSFileManager将文件写到应用的目录下(一般来说这种可以重复获得的内容应该放到cache目录下),因为当你从这个委托方法返回时,该文件将从临时存储中删除。

创建后台下载的操作步骤

后台传输的的实现也十分简单,简单说分为三个步骤:

1:创建后台下载用的NSURLSession对象,设置为后台下载类型;

2:向这个对象中加入对应的传输的NSURLSessionTask,并开始下载;

3:在AppDelegate里实现handleEventsForBackgroundURLSession,以刷新UI及通知系统传输结束。

4:实现NSURLSessionDownloadDelegate中必要的代理

具体代码实现

1:创建一个后台下载对象用dispatch_once创建一个用于后台下载对象,目的是为了保证identifier的唯一,文档不建议对于相同的标识符 (identifier) 创建多个会话对象。这里创建并配置了NSURLSession,将通过backgroundSessionConfiguration其指定为后台session并设定delegate。

- (NSURLSession*)backgroundURLSession {staticNSURLSession*session =nil;staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSString*identifier =@"com.yourcompany.appId.BackgroundSession";NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfigurationbackgroundSessionConfigurationWithIdentifier:identifier]; session = [NSURLSessionsessionWithConfiguration:sessionConfig delegate:selfdelegateQueue:[NSOperationQueuemainQueue]]; });returnsession;}

2:向其中加入对应的传输用的NSURLSessionTask,并调用resume启动下载。

- (void)beginDownloadWithUrl:(NSString*)downloadURLString {NSURL*downloadURL = [NSURLURLWithString:downloadURLString];NSURLRequest*request = [NSURLRequestrequestWithURL:downloadURL];NSURLSession*session = [selfbackgroundURLSession];NSURLSessionDownloadTask*downloadTask = [session downloadTaskWithRequest:request]; [downloadTask resume];}

3.在appDelegate中实现handleEventsForBackgroundURLSession,要注意的是,需要在handleEventsForBackgroundURLSession中必须重新建立一个后台 session 的参照(可以用之前dispatch_once创建的对象),否则NSURLSessionDownloadDelegate和NSURLSessionDelegate方法会因为没有 对 session 的 delegate 设置而不会被调用。然后保存completionHandler()。

- (void)application:(UIApplication*)applicationhandleEventsForBackgroundURLSession:(NSString*)identifier completionHandler:(void(^)())completionHandler {NSURLSession*backgroundSession = [selfbackgroundURLSession];NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession);// 保存 completion handler 以在处理 session 事件后更新 UI[selfaddCompletionHandler:completionHandler forSession:identifier]; }

- (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString*)identifier {if([self.completionHandlerDictionary objectForKey:identifier]) {NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.\n"); } [self.completionHandlerDictionary setObject:handler forKey:identifier];}

注:handleEventsForBackgroundURLSession方法是在后台下载的所有任务完成后才会调用。如果当后台传输完成时,如果应用程序已经被杀掉,iOS将会在后台启动该应用程序,下载相关的委托方法会在application:didFinishLaunchingWithOptions:方法被调用之后被调用。

4:实现URLSessionDidFinishEventsForBackgroundURLSession,待所有数据处理完成,UI刷新之后在改方法中在调用之前保存的completionHandler()。

//NSURLSessionDelegate委托方法,会在NSURLSessionDownloadDelegate委托方法后执行- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession*)session {NSLog(@"Background URL session %@ finished events.\n", session);if(session.configuration.identifier) {// 调用在 -application:handleEventsForBackgroundURLSession: 中保存的 handler[selfcallCompletionHandlerForSession:session.configuration.identifier]; }} - (void)callCompletionHandlerForSession:(NSString*)identifier { CompletionHandlerType handler = [self.completionHandlerDictionary objectForKey: identifier];if(handler) { [self.completionHandlerDictionary removeObjectForKey: identifier];NSLog(@"Calling completion handler for session %@", identifier); handler(); }}

关于断点下载可能还会问到的问题

如何暂停下载,暂停后,如何继续下载?有两种方法

@第一种,使用cancelByProducingResumeData

/* 对某一个NSURLSessionDownloadTask取消下载,取消后会回调给我们 resumeData,

    * resumeData包含了下载任务的一些状态,之后可以用户恢复下载

  */- (void)cancelByProducingResumeData:(void(^)(NSData* resumeData))completionHandler;

调用该方法会触发以下方法,会附带resumeData,用于恢复。

- (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error

对应恢复方法

//通过之前保存的resumeData,获取断点的NSURLSessionTask,调用resume恢复下载NSURLSessionDownloadTask*task = [[selfbackgroundURLSession] downloadTaskWithResumeData:resumeData];[task resume];

第二种,使用NSURLSessionDownloadTask的suspend方法

//暂停[self.downloadTask suspend];

//恢复[self.downloadTask resume];

通过以上的两个方法,就可以实现下载的暂停与恢复下载了

下载失败后,如何恢复下载?--下载失败后,可以通过以下代码来恢复下载

/* 该方法下载成功和失败都会回调,只是失败的是error是有值的,

  * 在下载失败时,error的userinfo属性可以通过NSURLSessionDownloadTaskResumeData

  * 这个key来取到resumeData(和上面的resumeData是一样的),再通过resumeData恢复下载

  */- (void)URLSession:(NSURLSession*)sessiona              task:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error {if(error) {// check if resume data are availableif([error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]) {NSData*resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData];NSURLSessionTask*task = [[selfbackgroundURLSession] downloadTaskWithResumeData:resumeData];            [task resume];        }    }}

应用被用户杀掉后,如何恢复之前的下载?

在应用被杀掉前,iOS系统保存应用下载sesson的信息,在重新启动应用,并且创建和之前相同identifier的session时(苹果通过identifier找到对应的session数据),iOS系统会对之前下载中的任务进行依次回调URLSession:task:didCompleteWithError:方法,之后可以使用上面提到的下载失败时的处理方法进行恢复下载


//www.greatytc.com/p/1211cf99dfc3

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

推荐阅读更多精彩内容