之前写过一系列Unity3d的上 googleplay 与分包操作,但是在实际应用中你会发现,由于资源包(.obb)可能过大,然后移动网络又可能出于不稳定状态,(2b公司的网络都是这样 的) ,那么你的下载 很可能一天都下不完(因为由于没有一次完整下载过 所以 重复下载)。
之前查过一些文章来实现这个功能,但是unity的www根本不支持断点续传的功能,而是一个阻塞的(要么得到我的全部,要么啥都别想要,感觉unity后续版本会考虑加入断点这个功能) 所有这里我们参考了国外的一些文章,然后实现了断点续传的功能。
解释一下断点续传:所谓断点续传就是指资源下载到了某一个阶段,然后由于某些特殊的情况导致下载中断,下次进入下载的时候会从中断的地方下载,而不是又重头来过。(口水解释,不过意思大概就是这个样子了)
断点续传的原理:大概如下图
代码实现
// 获取文件头,文件大小修改日期等等
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(remoteFile);
//文件头标志 (上图 第一,二步奏)
<span style="font-family: Arial, Helvetica, sans-serif;">request.Method = "HEAD"; </span>
HttpWebResponse resp = null;
try {
resp = (HttpWebResponse)request.GetResponse();
}
catch (System.Exception e) {
}
mRemoteLastModified = resp.LastModified;
mRemoteFileSize = resp.ContentLength;
resp.Close();
// 下载步骤
public IEnumerator Download() {
if (mHadError) { yield break; }
while (gDownloadIsRunning)
yield return null;
gDownloadIsRunning = true;
long localFileSize = (File.Exists(mLocalFile))? (new FileInfo(mLocalFile)).Length : 0;
if (localFileSize == mRemoteFileSize && !IsOutdated) {
Log("File already cacled, not downloading: " + mLocalFile);
gDownloadIsRunning = false;
yield break; // We already have the file, early out
}
else if (localFileSize > mRemoteFileSize || IsOutdated) {
if (!IsOutdated) Debug.LogWarning("Local file is larger than remote file, but not outdated. PANIC!");
if (IsOutdated) Debug.Log("Local file is outdated, deleting");
try {
if (File.Exists(mLocalFile))
File.Delete(mLocalFile);
}
catch (System.Exception e) {
Debug.LogWarning("<color=red>Could not delete local file</color>");
Debug.LogError(e);
}
while (File.Exists(mLocalFile))
yield return null;
localFileSize = 0;
}
#if UseWebClient || UNITY_IOS
using (WebClient client = new WebClient()) {
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
client.DownloadFileAsync(new Uri(mRemoteFile), mLocalFile);
}
while (!done)
yield return null;
#else
int bufferSize = 1024 * 1000;
Log("[Downloading: " + mRemoteFile);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(mRemoteFile);
request.Timeout = 30000;
showSize = localFileSize;
totalSize = mRemoteFileSize-1;
Debug.Log("init show size = " + showSize);
request.AddRange((int)localFileSize, (int)mRemoteFileSize - 1);
request.Method = WebRequestMethods.Http.Get; //这里被我改了,之前post 但是一直报错 405
request.BeginGetResponse(AsynchCallback, request);
while (mAsynchResponse == null) // Wait for asynch to finish
yield return null;
Stream inStream = mAsynchResponse.GetResponseStream();
FileStream outStream = new FileStream(mLocalFile, (localFileSize > 0)? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
int count = 0;
byte[] buff = new byte[bufferSize];
while ((count = inStream.Read(buff, 0, bufferSize)) > 0) {
showProgress(showSize, totalSize);
showSize+=count;
outStream.Write(buff, 0, count);
outStream.Flush();
yield return null;
}
outStream.Flush();
outStream.Close();
inStream.Close();
request.Abort();
mAsynchResponse.Close();
mAsynchResponse = null;
localFileSize = (File.Exists(mLocalFile))? (new FileInfo(mLocalFile)).Length : 0;
while(localFileSize != mRemoteFileSize) {
localFileSize = (File.Exists(mLocalFile))? (new FileInfo(mLocalFile)).Length : 0;
yield return null;
}
#endif
gDownloadIsRunning = false;
}