BundleDownloaderComponent.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. namespace ET
  6. {
  7. public class BundleDownloaderComponentAwakeSystem : AwakeSystem<BundleDownloaderComponent>
  8. {
  9. public override void Awake(BundleDownloaderComponent self)
  10. {
  11. self.bundles = new Queue<string>();
  12. self.downloadedBundles = new HashSet<string>();
  13. }
  14. }
  15. /// <summary>
  16. /// 用来对比web端的资源,比较md5,对比下载资源
  17. /// </summary>
  18. public class BundleDownloaderComponent : Entity
  19. {
  20. private VersionConfig remoteVersionConfig;
  21. public Queue<string> bundles;
  22. public long TotalSize;
  23. public HashSet<string> downloadedBundles;
  24. //多任务同时下载
  25. public List<UnityWebRequestAsync> webRequests = new List<UnityWebRequestAsync>();
  26. public override void Dispose()
  27. {
  28. if (this.IsDisposed)
  29. {
  30. return;
  31. }
  32. if (this.Parent.IsDisposed)
  33. {
  34. return;
  35. }
  36. base.Dispose();
  37. this.remoteVersionConfig = null;
  38. this.TotalSize = 0;
  39. this.bundles = null;
  40. this.downloadedBundles = null;
  41. foreach (UnityWebRequestAsync webRequest in this.webRequests)
  42. {
  43. webRequest.Dispose();
  44. }
  45. webRequests.Clear();
  46. this.Parent.RemoveComponent<BundleDownloaderComponent>();
  47. }
  48. public async ETTask StartAsync(string url)
  49. {
  50. // 获取远程的Version.txt
  51. string versionUrl = "";
  52. try
  53. {
  54. using (UnityWebRequestAsync webRequestAsync = EntityFactory.Create<UnityWebRequestAsync>(this.Domain))
  55. {
  56. versionUrl = url + "StreamingAssets/" + "Version.txt";
  57. //Log.Debug(versionUrl);
  58. await webRequestAsync.DownloadAsync(versionUrl);
  59. remoteVersionConfig = JsonHelper.FromJson<VersionConfig>(webRequestAsync.Request.downloadHandler.text);
  60. //Log.Debug(JsonHelper.ToJson(this.VersionConfig));
  61. }
  62. }
  63. catch (Exception e)
  64. {
  65. throw new Exception($"url: {versionUrl}", e);
  66. }
  67. // 获取streaming目录的Version.txt
  68. VersionConfig streamingVersionConfig;
  69. string versionPath = Path.Combine(PathHelper.AppResPath4Web, "Version.txt");
  70. using (UnityWebRequestAsync request = EntityFactory.Create<UnityWebRequestAsync>(this.Domain))
  71. {
  72. await request.DownloadAsync(versionPath);
  73. streamingVersionConfig = JsonHelper.FromJson<VersionConfig>(request.Request.downloadHandler.text);
  74. }
  75. // 删掉远程不存在的文件
  76. DirectoryInfo directoryInfo = new DirectoryInfo(PathHelper.AppHotfixResPath);
  77. if (directoryInfo.Exists)
  78. {
  79. FileInfo[] fileInfos = directoryInfo.GetFiles();
  80. foreach (FileInfo fileInfo in fileInfos)
  81. {
  82. if (remoteVersionConfig.FileInfoDict.ContainsKey(fileInfo.Name))
  83. {
  84. continue;
  85. }
  86. if (fileInfo.Name == "Version.txt")
  87. {
  88. continue;
  89. }
  90. fileInfo.Delete();
  91. }
  92. }
  93. else
  94. {
  95. directoryInfo.Create();
  96. }
  97. // 对比MD5
  98. foreach (FileVersionInfo fileVersionInfo in remoteVersionConfig.FileInfoDict.Values)
  99. {
  100. // 对比md5
  101. string localFileMD5 = BundleHelper.GetBundleMD5(streamingVersionConfig, fileVersionInfo.File);
  102. if (fileVersionInfo.MD5 == localFileMD5)
  103. {
  104. continue;
  105. }
  106. this.bundles.Enqueue(fileVersionInfo.File);
  107. this.TotalSize += fileVersionInfo.Size;
  108. }
  109. }
  110. public int Progress
  111. {
  112. get
  113. {
  114. if (this.TotalSize == 0)
  115. {
  116. return 0;
  117. }
  118. long alreadyDownloadBytes = 0;
  119. //已经下载完成的
  120. foreach (string downloadedBundle in this.downloadedBundles)
  121. {
  122. alreadyDownloadBytes += this.remoteVersionConfig.FileInfoDict[downloadedBundle].Size;
  123. }
  124. //当前正在下载的
  125. foreach (UnityWebRequestAsync webRequest in webRequests)
  126. {
  127. alreadyDownloadBytes += (long) webRequest.Request.downloadedBytes;
  128. }
  129. return (int)(alreadyDownloadBytes * 100f / this.TotalSize);
  130. }
  131. }
  132. public async ETTask DownloadAsync(string url)
  133. {
  134. if (this.bundles.Count == 0)
  135. {
  136. return;
  137. }
  138. try
  139. {
  140. //正在下载的文件个数
  141. int downloadingCount = 0;
  142. //下载单个文件
  143. async void downloadFile()
  144. {
  145. if (this.bundles.Count == 0)
  146. return;
  147. downloadingCount++;
  148. //取出一个进行下载
  149. string downloading = this.bundles.Dequeue();
  150. Log.Debug($"开始下载({downloadingCount}):{downloading}");
  151. try
  152. {
  153. using (UnityWebRequestAsync webRequest = EntityFactory.Create<UnityWebRequestAsync>(this.Domain))
  154. {
  155. webRequests.Add(webRequest);
  156. await webRequest.DownloadAsync(url + "StreamingAssets/" + downloading);
  157. byte[] data = webRequest.Request.downloadHandler.data;
  158. webRequests.Remove(webRequest);
  159. string path = Path.Combine(PathHelper.AppHotfixResPath, downloading);
  160. using (FileStream fs = new FileStream(path, FileMode.Create))
  161. {
  162. fs.Write(data, 0, data.Length);
  163. }
  164. }
  165. }
  166. catch (Exception e)
  167. {
  168. //下载异常跳过
  169. Log.Error($"download bundle error: {downloading}\n{e}");
  170. }
  171. finally
  172. {
  173. downloadingCount--;
  174. }
  175. //正常下载
  176. this.downloadedBundles.Add(downloading);
  177. Log.Debug($"download bundle Finish: {downloading}\n");
  178. }
  179. /*
  180. //最多同时下载n个文件 下载40M(400~500)个文件测试时间(ms)对比
  181. //等待n个任务同时完成再继续 1~61616 2~44796 3~34377 4~31918 5~27184 6~25564 7~22817 8~22719
  182. //完成1个补充1个最大n个任务 1~61309 8~11871 9~10843 10~10600 15~9309 20~9146 100~9195
  183. */
  184. //最大任务数量20 速度从61秒提升到9秒
  185. int maxCount = 20;
  186. while (true)
  187. {
  188. await TimerComponent.Instance.WaitAsync(10);
  189. //需要下载队列取完 正在下载为0表示完成更新
  190. if (this.bundles.Count == 0 && downloadingCount == 0)
  191. break;
  192. for (int i = downloadingCount; i < maxCount; i++)
  193. downloadFile();
  194. }
  195. }
  196. catch (Exception e)
  197. {
  198. Log.Error(e);
  199. }
  200. }
  201. }
  202. }