/////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////断点续存的方式下载网络资源///////////////////////////////////////// /////////////////////////TODO:UI显示下载进度///暂时使用打印替代(平板不需要)////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; public class DownloadAssets : MonoBehaviour { public static DownloadAssets Instance; //五亿字节为一段 0.1G 100mb double loadedBytes = 100000000; /// /// 存放正在下载资源的UWR事件 /// internal Dictionary AssetsUWR = new Dictionary(); /// /// 创建新的资源图标 /// internal UnityEvent CreateAssetcell = new UnityEvent(); /// /// 更新资源图标 /// internal UnityEvent UpdateAssetcell = new UnityEvent(); /// /// 删除资源图标 /// internal UnityEvent DeleteAssetcell = new UnityEvent(); void Awake() { if (Instance == null) Instance = this; } /// /// 下载资源 /// /// 资源url /// 本地存放位置 /// 资源信息 /// 是否是新增资源 /// 是否是封面 public void DownLoad(string fullUrl, string savePath, Assets assets, bool isAdded, bool isIcon) { //完整的接口 fullUrl = WebNet.DownAssetsUrl + fullUrl; //Debug.Log(fullUrl); StartCoroutine(RenewDownLoad(fullUrl, savePath, assets, isAdded, isIcon)); } /// /// 断点续存 /// /// 资源url /// 本地存放位置 IEnumerator RenewDownLoad(string fullUrl, string savePath, Assets assets, bool isAdded, bool isIcon) { long countLength; using (UnityWebRequest uwrGetCount = UnityWebRequest.Head(fullUrl)) { yield return uwrGetCount.SendWebRequest(); //获取资源字节长度 long.TryParse(uwrGetCount.GetResponseHeader("Content-Length"), out countLength); //Debug.Log($"{savePath}:{countLength}"); } //long countLength = assets.file_size; ////Debug.LogError(fullUrl); //if (assets.file_size > 1000000) //{ // using (UnityWebRequest uwrGetCount = UnityWebRequest.Head(fullUrl)) // { // yield return uwrGetCount.SendWebRequest(); // //获取资源字节长度 // countLength = long.Parse(uwrGetCount.GetResponseHeader("Content-Length")); // //Debug.Log($"{savePath}:{countLength}"); // } //} using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(fullUrl)) { //append设置为true文件写入方式为接续写入,不覆盖原文件。 unityWebRequest.downloadHandler = new DownloadHandlerFile(savePath, true); //创建文件 FileInfo file = new FileInfo(savePath); string filename = Path.GetFileName(savePath);//资源名字 if (!AssetsUWR.ContainsKey(filename)) AssetsUWR.Add(filename, unityWebRequest); //当前下载的文件长度 long fileLength = file.Length; //请求网络数据从第fileLength到最后的字节 unityWebRequest.SetRequestHeader("Range", $"bytes={fileLength}-");//设置Range值 if (!string.IsNullOrEmpty(unityWebRequest.error)) { Debug.LogError($"下载失败{unityWebRequest.error}"); } string jsonPath = $"{Path.GetDirectoryName(savePath)}/{assets.resource_name}.json"; //Debug.Log(jsonPath); double currProgress = 0; if (fileLength < countLength) { unityWebRequest.SendWebRequest(); while (!unityWebRequest.isDone) { if (File.Exists(jsonPath)) { File.Delete(jsonPath); } double lastProgress = (double)fileLength / countLength;//上次下载的进度 //Debug.Log($"{savePath}上次下载:{(lastProgress * 100).ToString("0.00")}% "); double newProgress = unityWebRequest.downloadProgress; currProgress = lastProgress + newProgress * (1 - lastProgress); //Debug.Log($"{savePath}已经下载:{(currProgress * 100).ToString("0.00")}% "); if (savePath.Contains("mp4")) { //更新进度条 //UpdateVideoProgressUIEvent.Invoke(filename, currProgress); } else if (savePath.Contains("apk")) { //更新进度条 //UpdateAppProgressUIEvent.Invoke(filename, currProgress); } else { //其他资源更新进度条 } //超过一定的字节关闭现在的协程,开启新的协程,将资源分段下载 if (unityWebRequest.downloadedBytes >= loadedBytes) { Coroutine coroutine = StartCoroutine(RenewDownLoad(fullUrl, savePath, assets, isAdded, isIcon)); StopCoroutine(coroutine); //如果 UnityWebRequest 在进行中,就停止。 unityWebRequest.Abort(); AssetsUWR.Remove(filename); if (!string.IsNullOrEmpty(unityWebRequest.error)) { Debug.LogError($"{filename}下载失败:{unityWebRequest.error}"); } Debug.Log($"开启新的携程继续下载{filename}"); yield return StartCoroutine(RenewDownLoad(fullUrl, savePath, assets, isAdded, isIcon)); } yield return null; } } else { //资源是完整的 DoneRecordInfo(savePath, assets, isIcon); } if (unityWebRequest.downloadHandler.isDone) { DoneRecordInfo(savePath, assets, isAdded, isIcon); } } } /// /// 资源是完整的,直接记录下载完成信息 /// void DoneRecordInfo(string savePath, Assets assets, bool isIcon) { AssetsUWR.Remove(Path.GetFileName(savePath)); if (isIcon) return;//如果下载的是封面,则不记录 RecordDownloaddoneAssetsinfo(assets); } /// /// 下载完成记录信息 /// void DoneRecordInfo(string savePath, Assets assets, bool isAdded, bool isIcon) { AssetsUWR.Remove(Path.GetFileName(savePath)); string extension = Path.GetExtension(savePath).ToLower(); switch (assets.type)//1:apk 2:video 3:image 4:file 5:maps 6:pc应用 { case 1: if (isIcon) { //Debug.Log($"封面图片:{assets.resource_name}下载完成"); if (isAdded)//资源是新增 { Debug.Log("创建资源封面"); CreateAssetcell.Invoke(assets, savePath); } else//资源是更新 { Debug.Log("更改资源封面"); UpdateAssetcell.Invoke(assets, savePath); } return; } else { Debug.Log($"app资源:{assets.resource_name}下载完成"); //关闭下载进度条 PicoAPI._Instance.UnInstallApp(assets.brief); GameTools.Share.Delay(5f, () => { PicoAPI._Instance.InstallApk(savePath); }); } break; case 2: if (isIcon) { //Debug.Log($"封面图片:{assets.resource_name}下载完成"); if (isAdded)//资源是新增 { Debug.Log("创建资源封面"); CreateAssetcell.Invoke(assets, savePath); } else//资源是更新 { Debug.Log("更改资源封面"); UpdateAssetcell.Invoke(assets, savePath); } return; } else { Debug.Log($"mp4资源:{assets.resource_name}下载完成"); //关闭下载进度条 } break; case 3: Debug.Log($"图片资源:{assets.resource_name}下载完成"); //关闭下载进度条 break; case 4: Debug.Log($"文件资源:{assets.resource_name}下载完成"); //关闭下载进度条 break; case 5: Debug.Log($"地图资源:{assets.resource_name}下载完成"); //关闭下载进度条 break; case 6: if (isIcon) { //Debug.Log($"封面图片:{assets.resource_name}下载完成"); if (isAdded)//资源是新增 { Debug.Log("创建资源封面"); CreateAssetcell.Invoke(assets, savePath); } else//资源是更新 { Debug.Log("更改资源封面"); UpdateAssetcell.Invoke(assets, savePath); } return; } else { Debug.Log($"pc应用资源:{assets.resource_name}下载完成"); //关闭下载进度条 } break; default: //其他未知资源 Debug.Log($"其他资源:{assets.resource_name}下载完成"); break; } RecordDownloaddoneAssetsinfo(assets); } /// /// 记录下载完成的资源信息 /// public void RecordDownloaddoneAssetsinfo(Assets assets) { string json = JsonUtility.ToJson(assets); byte[] bytes = Encoding.UTF8.GetBytes(json); string path = $"{Config.AssetsInfoPath}/{assets.resource_name}.json"; GameTools.WriteFile(path, bytes); } private void OnDestroy() { foreach (var item in AssetsUWR.Values) { item.Abort(); } } }