iOS怎么進(jìn)行后臺(tái)下載,斷點(diǎn)下載

iOS怎么進(jìn)行后臺(tái)下載,斷點(diǎn)下載

從iOS7以來,蘋果阿爸推出NSURLSession后,iOS現(xiàn)在可以實(shí)現(xiàn)真正的后臺(tái)下載。

一個(gè)NSURLSession對象可以協(xié)調(diào)一個(gè)或多個(gè)NSURLSessionTask對象,并且根據(jù)NSURLSessionTask創(chuàng)建的NSURLSessionConfiguration實(shí)現(xiàn)不同的功能,使用相同的配置,你也可以創(chuàng)建多組具有相關(guān)任務(wù)的NSURLSession對象,要利用后臺(tái)傳輸服務(wù),你將會(huì)使用[NSURLSessionConfiguration backgroundSessionConfiguration]來創(chuàng)建一個(gè)會(huì)話配置,添加到后臺(tái)會(huì)話的任務(wù)在外部進(jìn)程運(yùn)行,即使應(yīng)用程序被掛起,崩潰,或者被殺死,它依然會(huì)運(yùn)行。

下面我們來看看如何使用NSURLSession

下載用到的委托方法

1:AppDelegate委托方法

//在應(yīng)用處于后臺(tái),且后臺(tái)任務(wù)下載完成時(shí)回調(diào) - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler; ?????????????????

2:NSURLSession委托方法

/* 在任務(wù)下載完成、下載失敗 * 或者是應(yīng)用被殺掉后,重新啟動(dòng)應(yīng)用并創(chuàng)建相關(guān)identifier的Session時(shí)調(diào)用 */ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error; ?

/* 應(yīng)用在后臺(tái),而且后臺(tái)所有下載任務(wù)完成后,

* 在所有其他NSURLSession和NSURLSessionDownloadTask委托方法執(zhí)行完后回調(diào),

* 可以在該方法中做下載數(shù)據(jù)管理和UI刷新 ?*/-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession*)session;

注:最好將handleEventsForBackgroundURLSession中completionHandler保存,在該方法中待所有載數(shù)據(jù)管理和UI刷新做完后,再調(diào)用completionHandler()

NSURLSessionDownloadTask委托方法

/* 下載過程中調(diào)用,用于跟蹤下載進(jìn)度

* bytesWritten為單次下載大小

* totalBytesWritten為當(dāng)當(dāng)前一共下載大小

* totalBytesExpectedToWrite為文件大小

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

/* 下載恢復(fù)時(shí)調(diào)用

* 在使用downloadTaskWithResumeData:方法獲取到對應(yīng)NSURLSessionDownloadTask,

* 并該task調(diào)用resume的時(shí)候調(diào)用

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

//下載完成時(shí)調(diào)用- (void)URLSession:(NSURLSession*)session? ? ? downloadTask:(NSURLSessionDownloadTask*)downloadTaskdidFinishDownloadingToURL:(NSURL*)location;

注:在URLSession:downloadTask:didFinishDownloadingToURL方法中,location只是一個(gè)磁盤上該文件的臨時(shí) URL,只是一個(gè)臨時(shí)文件,需要自己使用NSFileManager將文件寫到應(yīng)用的目錄下(一般來說這種可以重復(fù)獲得的內(nèi)容應(yīng)該放到cache目錄下),因?yàn)楫?dāng)你從這個(gè)委托方法返回時(shí),該文件將從臨時(shí)存儲(chǔ)中刪除。

創(chuàng)建后臺(tái)下載的操作步驟

后臺(tái)傳輸?shù)牡膶?shí)現(xiàn)也十分簡單,簡單說分為三個(gè)步驟:

1:創(chuàng)建后臺(tái)下載用的NSURLSession對象,設(shè)置為后臺(tái)下載類型;

2:向這個(gè)對象中加入對應(yīng)的傳輸?shù)腘SURLSessionTask,并開始下載;

3:在AppDelegate里實(shí)現(xiàn)handleEventsForBackgroundURLSession,以刷新UI及通知系統(tǒng)傳輸結(jié)束。

4:實(shí)現(xiàn)NSURLSessionDownloadDelegate中必要的代理

具體代碼實(shí)現(xiàn)

1:創(chuàng)建一個(gè)后臺(tái)下載對象用dispatch_once創(chuàng)建一個(gè)用于后臺(tái)下載對象,目的是為了保證identifier的唯一,文檔不建議對于相同的標(biāo)識(shí)符 (identifier) 創(chuàng)建多個(gè)會(huì)話對象。這里創(chuàng)建并配置了NSURLSession,將通過backgroundSessionConfiguration其指定為后臺(tái)session并設(shè)定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:向其中加入對應(yīng)的傳輸用的NSURLSessionTask,并調(diào)用resume啟動(dòng)下載。

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

3.在appDelegate中實(shí)現(xiàn)handleEventsForBackgroundURLSession,要注意的是,需要在handleEventsForBackgroundURLSession中必須重新建立一個(gè)后臺(tái) session 的參照(可以用之前dispatch_once創(chuàng)建的對象),否則NSURLSessionDownloadDelegate和NSURLSessionDelegate方法會(huì)因?yàn)闆]有 對 session 的 delegate 設(shè)置而不會(huì)被調(diào)用。然后保存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方法是在后臺(tái)下載的所有任務(wù)完成后才會(huì)調(diào)用。如果當(dāng)后臺(tái)傳輸完成時(shí),如果應(yīng)用程序已經(jīng)被殺掉,iOS將會(huì)在后臺(tái)啟動(dòng)該應(yīng)用程序,下載相關(guān)的委托方法會(huì)在application:didFinishLaunchingWithOptions:方法被調(diào)用之后被調(diào)用。

4:實(shí)現(xiàn)URLSessionDidFinishEventsForBackgroundURLSession,待所有數(shù)據(jù)處理完成,UI刷新之后在改方法中在調(diào)用之前保存的completionHandler()。

//NSURLSessionDelegate委托方法,會(huì)在NSURLSessionDownloadDelegate委托方法后執(zhí)行- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession*)session {NSLog(@"Background URL session %@ finished events.\n", session);if(session.configuration.identifier) {// 調(diào)用在 -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(); }}

關(guān)于斷點(diǎn)下載可能還會(huì)問到的問題

如何暫停下載,暫停后,如何繼續(xù)下載?有兩種方法

@第一種,使用cancelByProducingResumeData

/* 對某一個(gè)NSURLSessionDownloadTask取消下載,取消后會(huì)回調(diào)給我們 resumeData,

? ? * resumeData包含了下載任務(wù)的一些狀態(tài),之后可以用戶恢復(fù)下載

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

調(diào)用該方法會(huì)觸發(fā)以下方法,會(huì)附帶resumeData,用于恢復(fù)。

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

對應(yīng)恢復(fù)方法

//通過之前保存的resumeData,獲取斷點(diǎn)的NSURLSessionTask,調(diào)用resume恢復(fù)下載NSURLSessionDownloadTask*task = [[selfbackgroundURLSession] downloadTaskWithResumeData:resumeData];[task resume];

第二種,使用NSURLSessionDownloadTask的suspend方法

//暫停[self.downloadTask suspend];

//恢復(fù)[self.downloadTask resume];

通過以上的兩個(gè)方法,就可以實(shí)現(xiàn)下載的暫停與恢復(fù)下載了

下載失敗后,如何恢復(fù)下載?--下載失敗后,可以通過以下代碼來恢復(fù)下載

/* 該方法下載成功和失敗都會(huì)回調(diào),只是失敗的是error是有值的,

? * 在下載失敗時(shí),error的userinfo屬性可以通過NSURLSessionDownloadTaskResumeData

? * 這個(gè)key來取到resumeData(和上面的resumeData是一樣的),再通過resumeData恢復(fù)下載

? */- (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];? ? ? ? }? ? }}

應(yīng)用被用戶殺掉后,如何恢復(fù)之前的下載?

在應(yīng)用被殺掉前,iOS系統(tǒng)保存應(yīng)用下載sesson的信息,在重新啟動(dòng)應(yīng)用,并且創(chuàng)建和之前相同identifier的session時(shí)(蘋果通過identifier找到對應(yīng)的session數(shù)據(jù)),iOS系統(tǒng)會(huì)對之前下載中的任務(wù)進(jìn)行依次回調(diào)URLSession:task:didCompleteWithError:方法,之后可以使用上面提到的下載失敗時(shí)的處理方法進(jìn)行恢復(fù)下載


http://www.itdecent.cn/p/1211cf99dfc3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容