加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Unity手游之路<十二>手游资源热更新策略探讨

发布时间:2020-12-14 21:57:40 所属栏目:大数据 来源:网络整理
导读:版权声明:本文为博主原创文章,未经博主允许不得转载。 上一次我们学习了如何将资源进行打包。这次就可以用上场了,我们来探讨一下手游资源的增量更新策略。注意哦,只是资源哦。关于代码的更新,我们稍后再来研究。理论上这个方案可以使用各种静态资源的更

上一次我们学习了如何将资源进行打包。这次就可以用上场了,我们来探讨一下手游资源的增量更新策略。注意哦,只是资源哦。关于代码的更新,我们稍后再来研究。理论上这个方案可以使用各种静态资源的更新,不仅仅是assetbundle打包的。

(转载请注明原文地址http://www.voidcn.com/article/p-uzevsxxx-eo.html)

  • 原理
现在的手游安装有几种方式。一种是安装的时候就把程序和资源安装到本地。另外一种是只安装程序和少量的必要资源,然后在启动的时候再把缺少的资源下载完整。手游一般不建议和传统页游一样,在运行过程中加载资源,那样做会导致用户体验会比较差些。上述的两种安装模式,在更新资源上本质都是相同的。都是比较服务器资源的版本和本地资源的版本,以确定哪些资源要下载(包括需要更新的和新增的)。
  • 实践
? ? ? ? 1.资源打包。
资源打包之前,要先规划好资源之间的相互依赖关系。把一些共性的东西抽取出来,尽量减少不必要的耦合。一些比较好的做法有,所有物件尽可能做成Prefab,场景上的东西越少越好,“一切都是动态加载”。
? ? ? ??2.生成文件MD5
关于文件的MD5,这里就不详细描述了。大家可以简单理解它为一个文件的状态标记。如果文件有更改,那么它的md5一定是改变的,单纯的移动文件是不会更改的。md5验证还可以起到安全验证的作用,保证本地文件不被篡改。举个例子,我们经常从网上上下载软件时,一般都会给出一个md5值,你下载后,对比一下已下载文件的md5值,就可以知道文件有没有被篡改。在版本发布时,我们需要对所有打包好的文件计算md5值,然后保存在一个配置文件中。关于这部分的工作,我之前写过一个可视化小工具( https://github.com/kenro/File_Md5_Generator),现在分享给大家。如果大家觉得有用,记得打星哦:)
? ? ? ??3.版本比较
先加载本地的version.txt,将结果缓存起来。下载服务器的version.txt,与本地的version进行比较,筛选出需要更新和新增的资源
? ? ? ??4.下载资源
依次下载更新的资源,如果本地已经有旧资源,则替换之,否则就新建保存起来

? ? ? ??5.更新本地版本配置文件version.txt

用服务器的version.txt替换掉本地的version.txt。这样做是为了确保下次启动的时候,不会再重复更新了。

? ? ? ??6.从本地加载assetbundle进行测试显示。

这里将一个模型制成Prefab,打包成assetbundle。程序从本地加载后,显示在场景中

? ? ? ??7.更新服务器的assetbundle,重新生成版本号文件。

? ? ? ??8.重复6的步骤

我们可以验证,我们的程序不用任何改动,资源已经实现了更新。场景中显示的已经是最新的模型了。


关于上述的流程,我写了一个小的演示demo。我这里没有用到web服务器,而是将本地的另外一个文件夹作为资源服务器目录。这里的目录只针对windows下的版本进行测试。如果要在手机平台上,需要记得更新相关的路径。

[csharp] view plain copy print ?

  1. using?UnityEngine;??
  2. using?System.Collections;??
  3. using?System.Collections.Generic;??
  4. using?System.Text;??
  5. using?System.IO;??
  6. ??
  7. public?class?ResUpdate?:?MonoBehaviour??
  8. {??
  9. ????public?static?readonly?string?VERSION_FILE?=?"version.txt";??
  10. ????public?static?readonly?string?LOCAL_RES_URL?=?"file://"?+?Application.dataPath?+?"/Res/";??
  11. ????public?static?readonly?string?SERVER_RES_URL?=?"file:///C:/Res/";??
  12. ????public?static?readonly?string?LOCAL_RES_PATH?=?Application.dataPath?+?"/Res/";??
  13. ??
  14. ????private?Dictionary<string,?string>?LocalResVersion;??
  15. ????private?Dictionary<string,?string>?ServerResVersion;??
  16. ????private?List<string>?NeedDownFiles;??
  17. ????private?bool?NeedUpdateLocalVersionFile?=?false;??
  18. ??
  19. ????void?Start()??
  20. ????{??
  21. ????????//初始化??
  22. ????????LocalResVersion?=?new?Dictionary<string,?string>();??
  23. ????????ServerResVersion?=?new?Dictionary<string,?string>();??
  24. ????????NeedDownFiles?=?new?List<string>();??
  25. ??
  26. ????????//加载本地version配置??
  27. ????????StartCoroutine(DownLoad(LOCAL_RES_URL?+?VERSION_FILE,?delegate(WWW?localVersion)??
  28. ????????{??
  29. ????????????//保存本地的version??
  30. ????????????ParseVersionFile(localVersion.text,?LocalResVersion);??
  31. ????????????//加载服务端version配置??
  32. ????????????StartCoroutine(this.DownLoad(SERVER_RES_URL?+?VERSION_FILE,?delegate(WWW?serverVersion)??
  33. ????????????{??
  34. ????????????????//保存服务端version??
  35. ????????????????ParseVersionFile(serverVersion.text,?ServerResVersion);??
  36. ????????????????//计算出需要重新加载的资源??
  37. ????????????????CompareVersion();??
  38. ????????????????//加载需要更新的资源??
  39. ????????????????DownLoadRes();??
  40. ????????????}));??
  41. ??
  42. ????????}));??
  43. ????}??
  44. ??
  45. ????//依次加载需要更新的资源??
  46. ????private?void?DownLoadRes()??
  47. ????{??
  48. ????????if?(NeedDownFiles.Count?==?0)??
  49. ????????{??
  50. ????????????UpdateLocalVersionFile();??
  51. ????????????return;??
  52. ????????}??
  53. ??
  54. ????????string?file?=?NeedDownFiles[0];??
  55. ????????NeedDownFiles.RemoveAt(0);??
  56. ??
  57. ????????StartCoroutine(this.DownLoad(SERVER_RES_URL?+?file,?delegate(WWW?w)??
  58. ????????{??
  59. ????????????//将下载的资源替换本地就的资源??
  60. ????????????ReplaceLocalRes(file,?w.bytes);??
  61. ????????????DownLoadRes();??
  62. ????????}));??
  63. ????}??
  64. ??
  65. ????private?void?ReplaceLocalRes(string?fileName,?byte[]?data)??
  66. ????{??
  67. ????????string?filePath?=?LOCAL_RES_PATH?+?fileName;??
  68. ????????FileStream?stream?=?new?FileStream(LOCAL_RES_PATH?+?fileName,?FileMode.Create);??
  69. ????????stream.Write(data,?0,?data.Length);??
  70. ????????stream.Flush();??
  71. ????????stream.Close();??
  72. ????}??
  73. ??
  74. ????//显示资源??
  75. ????private?IEnumerator?Show()??
  76. ????{??
  77. ????????WWW?asset?=?new?WWW(LOCAL_RES_URL?+?"cube.assetbundle");??
  78. ????????yield?return?asset;??
  79. ????????AssetBundle?bundle?=?asset.assetBundle;??
  80. ????????Instantiate(bundle.Load("Cube"));??
  81. ????????bundle.Unload(false);??
  82. ????}??
  83. ??
  84. ????//更新本地的version配置??
  85. ????private?void?UpdateLocalVersionFile()??
  86. ????{??
  87. ????????if?(NeedUpdateLocalVersionFile)??
  88. ????????{??
  89. ????????????StringBuilder?versions?=?new?StringBuilder();??
  90. ????????????foreach?(var?item?in?ServerResVersion)??
  91. ????????????{??
  92. ????????????????versions.Append(item.Key).Append(",").Append(item.Value).Append("n");??
  93. ????????????}??
  94. ??
  95. ????????????FileStream?stream?=?new?FileStream(LOCAL_RES_PATH?+?VERSION_FILE,?FileMode.Create);??
  96. ????????????byte[]?data?=?Encoding.UTF8.GetBytes(versions.ToString());??
  97. ????????????stream.Write(data,?data.Length);??
  98. ????????????stream.Flush();??
  99. ????????????stream.Close();??
  100. ????????}??
  101. ????????//加载显示对象??
  102. ????????StartCoroutine(Show());??
  103. ????}??
  104. ??
  105. ????private?void?CompareVersion()??
  106. ????{??
  107. ????????foreach?(var?version?in?ServerResVersion)??
  108. ????????{??
  109. ????????????string?fileName?=?version.Key;??
  110. ????????????string?serverMd5?=?version.Value;??
  111. ????????????//新增的资源??
  112. ????????????if?(!LocalResVersion.ContainsKey(fileName))??
  113. ????????????{??
  114. ????????????????NeedDownFiles.Add(fileName);??
  115. ????????????}??
  116. ????????????else??
  117. ????????????{??
  118. ????????????????//需要替换的资源??
  119. ????????????????string?localMd5;??
  120. ????????????????LocalResVersion.TryGetValue(fileName,?out?localMd5);??
  121. ????????????????if?(!serverMd5.Equals(localMd5))??
  122. ????????????????{??
  123. ????????????????????NeedDownFiles.Add(fileName);??
  124. ????????????????}??
  125. ????????????}??
  126. ????????}??
  127. ????????//本次有更新,同时更新本地的version.txt??
  128. ????????NeedUpdateLocalVersionFile?=?NeedDownFiles.Count?>?0;??
  129. ????}??
  130. ??
  131. ????private?void?ParseVersionFile(string?content,?Dictionary<string,?string>?dict)??
  132. ????{??
  133. ????????if?(content?==?null?||?content.Length?==?0)??
  134. ????????{??
  135. ????????????return;??
  136. ????????}??
  137. ????????string[]?items?=?content.Split(new?char[]?{?'n'?});??
  138. ????????foreach?(string?item?in?items)??
  139. ????????{??
  140. ????????????string[]?info?=?item.Split(new?char[]?{?','?});??
  141. ????????????if?(info?!=?null?&&?info.Length?==?2)??
  142. ????????????{??
  143. ????????????????dict.Add(info[0],?info[1]);??
  144. ????????????}??
  145. ????????}??
  146. ??
  147. ????}??
  148. ??
  149. ????private?IEnumerator?DownLoad(string?url,?HandleFinishDownload?finishFun)??
  150. ????{??
  151. ????????WWW?www?=?new?WWW(url);??
  152. ????????yield?return?www;??
  153. ????????if?(finishFun?!=?null)??
  154. ????????{??
  155. ????????????finishFun(www);??
  156. ????????}??
  157. ????????www.Dispose();??
  158. ????}??
  159. ??
  160. ????public?delegate?void?HandleFinishDownload(WWW?www);??
  161. }??

  • 总结
资源更新的原理,本质上都是相似的。我之前也从事过页游的开发,资源更新流程也类似。所以技术的本质是掌握思维方式,平台和语言都是永远在变的。我们最后归纳一下流程:比较服务端的资源版本和本地的资源版本,找出需要更新的资源,然后依次下载。如果大家有更好的策略,欢迎分享探讨 ken@iamcoding.com。

  • 源码

http://pan.baidu.com/s/1mgNnR8O

  • 参考资料

Unity3d官网文档

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读