HotUpdate.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. var UpdatePanel = require('UpdatePanel');
  2. var Global = require("Global");
  3. const JSB_MD5 = require("jsb_md5");
  4. // var customManifestStr = JSON.stringify();
  5. cc.Class({
  6. extends: cc.Component,
  7. editor: {
  8. executionOrder: -1
  9. },
  10. properties: {
  11. panel: UpdatePanel,
  12. manifestUrl: {
  13. default: null,
  14. type: cc.Asset
  15. },
  16. updateUI: cc.Node,
  17. _updating: false,
  18. _canRetry: false,
  19. _storagePath: ''
  20. },
  21. checkCb: function (event) {
  22. // Global.print('checkCb Code: ' + event.getEventCode());
  23. switch (event.getEventCode())
  24. {
  25. case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
  26. Global.print("No local manifest file found, hot update skipped.");
  27. break;
  28. case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
  29. case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
  30. Global.print("Fail to download manifest file, hot update skipped.");
  31. break;
  32. case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
  33. Global.print("Already up to date with the latest remote version.");
  34. // this.node.getComponent("Login").showVersionInfo();
  35. this.node.getComponent("Login").ready2Login();
  36. cc.userOperate.sendRecord("no Update");
  37. break;
  38. case jsb.EventAssetsManager.NEW_VERSION_FOUND:
  39. Global.print('New version found, please try to update. (' + this._am.getTotalBytes() + ')');
  40. // this.panel.checkBtn.active = false;
  41. this.panel.fileProgress.progress = 0;
  42. this.panel.byteProgress.progress = 0;
  43. // Global.print(this._am.getTotalBytes());
  44. //启动更新
  45. this._updating = false;
  46. this._updateStartTime = Date.now();
  47. cc.userOperate.sendRecord("start Hotupdate");
  48. this.node.getComponent("Login").hideRightPanel();
  49. this.node.getComponent("Login").hideWaitting();
  50. this.show();
  51. this.hotUpdate();
  52. return;
  53. default:
  54. return;
  55. }
  56. // Global.print("1this._am.setEventCallback(null);");
  57. this._am.setEventCallback(null);
  58. this._checkListener = null;
  59. this._updating = false;
  60. },
  61. updateCb: function (event) {
  62. // Global.print('updateCb Code: ' + event.getEventCode());
  63. var needRestart = false;
  64. var failed = false;
  65. switch (event.getEventCode())
  66. {
  67. case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
  68. this.panel.info.string = 'No local manifest file found, hot update skipped.';
  69. failed = true;
  70. break;
  71. case jsb.EventAssetsManager.UPDATE_PROGRESSION:
  72. if (!isNaN(event.getPercent()))
  73. {
  74. this.panel.byteProgress.progress = event.getPercent();
  75. // this.panel.fileProgress.progress = event.getPercentByFile();
  76. // this.panel.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
  77. // this.panel.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();
  78. var msg = event.getMessage();
  79. if (msg) {
  80. // this.panel.info.string = 'Updated file: ' + msg;
  81. Global.print("getEventCode Updated file: "+msg);
  82. }
  83. }
  84. break;
  85. case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
  86. case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
  87. Global.print('Fail to download manifest file, hot update skipped.');
  88. failed = true;
  89. break;
  90. case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
  91. Global.print('Already up to date with the latest remote version.');
  92. failed = true;
  93. // this.node.getComponent("Login").showVersionInfo();
  94. this.node.getComponent("Login").ready2Login();
  95. break;
  96. case jsb.EventAssetsManager.UPDATE_FINISHED:
  97. Global.print('Update finished. ' + event.getMessage());
  98. needRestart = true;
  99. let updateTime = (Date.now() - this._updateStartTime) / 1000;
  100. cc.userOperate.sendRecord("hall-Average hot update duration", updateTime);
  101. this._updateStartTime = undefined;
  102. break;
  103. case jsb.EventAssetsManager.UPDATE_FAILED:
  104. Global.print('Update failed. ' + event.getMessage());
  105. // this.panel.retryBtn.active = true;
  106. this._updating = false;
  107. this._canRetry = true;
  108. this.retry();
  109. break;
  110. case jsb.EventAssetsManager.ERROR_UPDATING:
  111. Global.print('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage());
  112. break;
  113. case jsb.EventAssetsManager.ERROR_DECOMPRESS:
  114. Global.print(event.getMessage());
  115. break;
  116. default:
  117. break;
  118. }
  119. if (failed) {
  120. // Global.print("this._am.setEventCallback(null)")
  121. this._am.setEventCallback(null);
  122. this._updateListener = null;
  123. this._updating = false;
  124. }
  125. if (needRestart) {
  126. this._am.setEventCallback(null);
  127. this._updateListener = null;
  128. // Prepend the manifest's search path
  129. var searchPaths = jsb.fileUtils.getSearchPaths();
  130. var newPaths = this._am.getLocalManifest().getSearchPaths();
  131. // Global.print(JSON.stringify(newPaths));
  132. Array.prototype.unshift.apply(searchPaths, newPaths);
  133. // This value will be retrieved and appended to the default search path during game startup,
  134. // please refer to samples/js-tests/main.js for detailed usage.
  135. // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
  136. cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
  137. jsb.fileUtils.setSearchPaths(searchPaths);
  138. cc.userOperate.sendRecord("hotUpdate Success");
  139. //防止在重新加载过程中刷新IP(会出现闪崩)
  140. cc.ddos_refresh = false;
  141. cc.audioEngine.stopAll();
  142. //延迟0.5秒重启
  143. setTimeout(()=>{
  144. cc.game.restart();
  145. }, 500)
  146. // cc.game.restart();
  147. }
  148. },
  149. retry: function () {
  150. if (!this._updating && this._canRetry) {
  151. // this.panel.retryBtn.active = false;
  152. this._canRetry = false;
  153. // this.panel.info.string = 'Retry failed Assets...';
  154. this._am.downloadFailedAssets();
  155. }
  156. },
  157. removeAssets: function() {
  158. Global.print("清理热更新资源");
  159. jsb.fileUtils.removeDirectory(this._storagePath);
  160. },
  161. setManifestInfo(manifestInfo) {
  162. if(manifestInfo) {
  163. this.manifestUrl = manifestInfo;
  164. }
  165. },
  166. checkUpdate: function () {
  167. if (this._updating) {
  168. return;
  169. }
  170. if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
  171. // Resolve md5 url
  172. var url = this.manifestUrl.nativeUrl;
  173. if (cc.loader.md5Pipe) {
  174. url = cc.loader.md5Pipe.transformURL(url);
  175. }
  176. this._am.loadLocalManifest(url);
  177. }
  178. Global.print(this._am);
  179. if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
  180. Global.print("Failed to load local manifest ...123");
  181. return;
  182. }
  183. this._am.setEventCallback(this.checkCb.bind(this));
  184. this._am.checkUpdate();
  185. this._updating = true;
  186. },
  187. hotUpdate: function () {
  188. if (this._am && !this._updating) {
  189. this._am.setEventCallback(this.updateCb.bind(this));
  190. if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
  191. // Resolve md5 url
  192. var url = this.manifestUrl.nativeUrl;
  193. if (cc.loader.md5Pipe) {
  194. url = cc.loader.md5Pipe.transformURL(url);
  195. }
  196. this._am.loadLocalManifest(url);
  197. }
  198. this._failCount = 0;
  199. this._am.update();
  200. // this.panel.updateBtn.active = false;
  201. this._updating = true;
  202. }
  203. },
  204. show: function () {
  205. if (this.updateUI.active === false) {
  206. this.updateUI.active = true;
  207. }
  208. },
  209. // use this for initialization
  210. onLoad: function () {
  211. Global.print("执行HotUpdate onLoad");
  212. // Hot update is only available in Native build
  213. if (!cc.sys.isNative) {
  214. return;
  215. }
  216. this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');
  217. Global.print('Storage path for remote asset : ' + this._storagePath);
  218. //版本比较函数
  219. // 返回<0表示需要更新
  220. this.versionCompareHandle = function (localVersion, tarVersion) {
  221. Global.print("JS Custom Version Compare: localVersion is " + localVersion + ', tarVersion is ' + tarVersion);
  222. var a = parseInt(localVersion);
  223. var b = parseInt(tarVersion);
  224. return a - b;
  225. };
  226. var self = this;
  227. // Init with empty manifest url for testing custom manifest
  228. this._am = new jsb.AssetsManager('', this._storagePath, this.versionCompareHandle);
  229. // Global.print("+++++++++++++++++");
  230. // Global.print(JSON.stringify(this._am));
  231. var panel = this.panel;
  232. // Setup the verification callback, but we don't have md5 check function yet, so only print some message
  233. // Return true if the verification passed, otherwise return false
  234. this._am.setVerifyCallback(function (path, asset) {
  235. //TODO 下载后的文件再做一次md5校验,此处未实现
  236. //下载过程中仍然有小概率可能由于网络原因或其他网络库的问题导致下载的文件内容有问题
  237. // var md5 = calculateMD5(path);
  238. // if (md5 === asset.md5)
  239. // return true;
  240. // else
  241. // return false;
  242. cc.log("setVerifyCallback " + JSON.stringify(asset));
  243. // When asset is compressed, we don't need to check its md5, because zip file have been deleted.
  244. var compressed = asset.compressed;
  245. // Retrieve the correct md5 value.
  246. var expectedMD5 = asset.md5;
  247. // asset.path is relative path and path is absolute.
  248. var relativePath = asset.path;
  249. // The size of asset file, but this value could be absent.
  250. var size = asset.size;
  251. if (compressed) {
  252. // panel.info.string = "Verification passed : " + relativePath;
  253. return true;
  254. }
  255. else {
  256. // panel.info.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
  257. // return true;
  258. /*var filePath = self._storagePath + "_temp/"+ asset.path;
  259. if(!jsb.fileUtils.isFileExist(filePath)){
  260. cc.log("file doesn't exist " + asset.path);
  261. return false;
  262. }*/
  263. var resMD5 = JSB_MD5(jsb.fileUtils.getDataFromFile(path));
  264. return asset.md5 == resMD5;
  265. }
  266. });
  267. // this.panel.info.string = 'Hot update is ready, please check or directly update.';
  268. if (cc.sys.os === cc.sys.OS_ANDROID && cc.sys.isNative) {
  269. // Some Android device may slow down the download process when concurrent tasks is too much.
  270. // The value may not be accurate, please do more test and find what's most suitable for your game.
  271. this._am.setMaxConcurrentTask(2);
  272. // this.panel.info.string = "Max concurrent tasks count have been limited to 2";
  273. }
  274. this.panel.fileProgress.progress = 0;
  275. this.panel.byteProgress.progress = 0;
  276. },
  277. onDestroy: function () {
  278. }
  279. });