---2018-09-5補充-----
1.如果使用斷點續(xù)傳,不僅僅是客戶端的工作,還需要服務(wù)器支持?jǐn)帱c續(xù)傳功能,否則無法生成正確的resumeData,
如何驗證服務(wù)器是否支持?jǐn)帱c續(xù)傳呢?
我們可以通過下載文件的時候的響應(yīng)頭來查看:
根據(jù) 蘋果官方文檔描述:
滿足上述條件的 才能使用斷點續(xù)傳功能
其次,使用斷點續(xù)傳的時候,客戶端請求的range是比如說是 19799+ ,服務(wù)器此時返回的文件的部分?jǐn)?shù)據(jù),服務(wù)器響應(yīng)碼必須是 206,不可以是200或者其他狀態(tài)碼,否則客戶端會從頭下載,
---2018-09-5補充-----
先說說斷點續(xù)傳 :
最近重構(gòu)公司代碼,公司需要做文件的斷點續(xù)傳,看了下之前的代碼和網(wǎng)上的代碼,大家還有好多是使用的NSURLConnection,
,一點一點的拼接data,然后斷開連接,再次連接的時候,將本地的data的長度,塞到請求頭里面設(shè)置range
[request setValue:rangeString forHTTPHeaderField:@"Range"];
這種的,但是我們的網(wǎng)絡(luò)請求是封裝的AFNetworking的,也發(fā)現(xiàn)AFNetworking也有NSURLSessionDownLoadTask,我們就拿過來接著就用了,其實AFNetworking也支持?jǐn)帱c續(xù)傳,而且支持的我感覺還是很完美的.
---2019-01-24補充----
如果是做下載工具或者使用的默認(rèn)的defaultConfig的話,需要注意一下iOS默認(rèn)的限制同一個服務(wù)器tcp連接的并發(fā)數(shù)量限制,否則會發(fā)現(xiàn) ,無論創(chuàng)建多少下載任務(wù),都是4個或者6個在運行,其他的在排隊,甚至還最后直接超時了
我整理了一下并發(fā)的一些基礎(chǔ)的個人理解: NSURLSession的最大并發(fā) HTTPMaximumConnectionsPerHost屬性使用場景
---2019-01-24補充----
首先,我們創(chuàng)建一個管理下載的manager及下載的配置,注意那個后臺任務(wù)的backgroundSessionConfigurationWithIdentifier是要確定的,要后臺下載的時候使用
注意代碼中的一個AF的通知監(jiān)聽,特別重要,后臺下載的回調(diào)及下載成功失敗的回調(diào),都是在這個通知里面(其實是AFNetworking封裝了,把回調(diào)信息都是通過通知傳遞的,在這里真的佩服AFNetworking作者,把通知用的這么出神入化,我是在這里重新對通知的認(rèn)知提高了一個大的階段,這里只是上了一點發(fā)送通知的地方,通知的userInfo帶了很多東西,詳細(xì)的大家可以看下AF的源碼)
AFURLSessionManager開始一個下載的時候,有兩個方法,分別是開始下載(重頭下載),繼續(xù)下載(需要傳入一個resumeData)
看方法名,作者就給我們做了斷點續(xù)傳的功能
介紹完這兩個方法名,我們介紹下第一個方法是怎么使用,和第二個是什么使用的,并且resumeData是在哪里獲取的
1.當(dāng)我們需要下載的時候,主動去調(diào)用downloadTaskWithRequest方法,根據(jù)下載地址url,去判斷本地是否有resumeData,這個類似SDWebImage的實現(xiàn),我們自己去維護(hù)這個對應(yīng)關(guān)系,可以存到本地一個plist文件里面,鍵值對對應(yīng) url:resumeData ,
- 開始下載的時候,去判斷當(dāng)前是否存在這個url:resumeData,存在的話,看一下長度是否大于零(當(dāng)用戶開始下載的時候,如果什么都沒下載到,就中斷下載,resumeData是nil,如果直接寫入plist是會崩潰的,我們可以寫一個空字符串,雖然不是一個類型,但是length都可以使用,不會太影響),大于零,就使用resumeData調(diào)用downloadTaskWithResumeData這個方法,然后去開始我們的任務(wù)
上面是兩個基本的方法介紹,這里介紹一下那個ResumeData在哪里獲取,什么時候獲取,
還是上面提到的那個通知 (是在NSURLSessionTaskDelegate 這個協(xié)議里面的- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error 這個方法發(fā)出了的,其實downLoadTask的成功,失敗,中斷都會調(diào)用這個方法),所以,我們需要去剛剛那個通知里面去看看到底都傳過來什么.
拿到了這個ResumeData,大家就可以區(qū)分使用什么時候開始斷點續(xù)傳,什么時候重新下載了
大家可以主動去將task 提前結(jié)束來觸發(fā)那個通知,一般不允許蜂窩下載的時候,會用到這個方法
后臺下載 :
后臺下載呢,其實上面初始化那個manger的時候,配置那個后臺配置的時候,已經(jīng)實現(xiàn)了后臺下載的過程,你可以嘗試下,你調(diào)回前臺,你的下載也在繼續(xù),只是這個時候,你的session被操作系統(tǒng)接過去了,操作系統(tǒng)去管理了,一旦你下載完成,會通知你(如果你的app還活著的時候),那么你的app死了的時候怎么辦呢,操作系統(tǒng)會給你留著,持有者,等你的app再次復(fù)活的時候,并且再次創(chuàng)建NSURLSessionConfiguration,有后臺任務(wù),并且后臺的backgroundSessionConfigurationWithIdentifier一致的話,操作系統(tǒng)會去調(diào)用你的原來的NSURLSessionTaskDelegate代理中的task的didCompleteWithError的方法,由于我們的使用的是AF封裝的,所以那個代理被AF接到并且提供了回調(diào)API的Block组砚,同時也通過通知處理了,所以還是會在我們之前監(jiān)聽的那個通知里面,和我們app活著的時候一樣一樣的,去發(fā)送那個AFNetworkingTaskDidCompleteNotification的通知,在這里 我們原來的處理邏輯不需要改變,
上面講的是我們進(jìn)入后臺,app慢慢的被系統(tǒng) 殺死 或者沒殺死的時候,那么,如果我正在下載著,app崩潰,或者被用戶手動強退怎么辦? 經(jīng)過驗證,其實是一樣的,出現(xiàn)這個情況后,操作系統(tǒng)監(jiān)聽到被殺死或者被中斷,也會幫我們持有這個session,然后把崩潰的一瞬間的ResumeData存著,等待我們再次創(chuàng)建相同后綴的session,那時候在調(diào)用回調(diào)---->af再發(fā)通知---->我們再存起來.
講了這么多,大家是不是特別好奇,這個resumeData到底是什么?
其實resumeData是一個data類型,大家可以轉(zhuǎn)成字符串,看一下里面的內(nèi)容
他的本質(zhì)是一個xml文件
AF在下載的時候(其實是調(diào)用的系統(tǒng)的下載方法),會將文件先下載到沙盒目錄下的temp文件夾中,生成一個后綴為tmp的文件,等我們下載完的時候,會將文件處理,然后移動到我們下載時設(shè)置的路徑下,這樣,我們的下載任務(wù)就完成了,
在上面的xml文件中,大家可以看到下載的url,當(dāng)前接受的文件大小,第幾次下載,還有臨時文件名等信息,其實本質(zhì)還是萬變不離其宗,但是感覺這樣用起來挺好的,既然用了AF了,就用到底吧,這樣 ,我們基本的斷點續(xù)傳和后臺下載是說完了,有錯誤希望大家指出,共同進(jìn)步,謝謝
對了,參考過一個同學(xué)關(guān)于后臺下載的講解,大家可以看一下
參考文章 http://www.reibang.com/p/1211cf99dfc3
附帶個人的demo地址 : https://github.com/yangfangkuo/downLoadTest/tree/master
對大家致敬,感謝