hotupdate.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /** @format */
  2. import {Log} from '../utils/LogUtils'
  3. export class HotOptions {
  4. OnVersionInfo: Function
  5. OnNeedToUpdate: Function
  6. OnNoNeedToUpdate: Function
  7. OnUpdateFailed: Function
  8. OnUpdateSucceed: Function
  9. OnUpdateProgress: Function
  10. check() {
  11. for (let key in this) {
  12. if (key !== 'check') {
  13. if (!this[key]) {
  14. Log.warn(`参数HotOptions.${key}未设置!`)
  15. return false
  16. }
  17. }
  18. }
  19. return true
  20. }
  21. }
  22. class Hot {
  23. _assetsMgr: jsb.AssetsManager = null
  24. _options: HotOptions = null
  25. _state = Hot.State.None
  26. static State = {
  27. None: 0,
  28. Check: 1,
  29. Update: 2,
  30. }
  31. // 检查更新
  32. checkUpdate() {
  33. if (!this._assetsMgr) {
  34. Log.warn('请先初始化')
  35. return false
  36. }
  37. if (this._assetsMgr.getState() === jsb.AssetsManager.State.UNINITED) {
  38. Log.error('未初始化')
  39. return false
  40. }
  41. if (!this._assetsMgr.getLocalManifest().isLoaded()) {
  42. console.log('加载本地 manifest 失败 ...')
  43. return false
  44. }
  45. this._assetsMgr.setEventCallback(this._checkUpdateCb.bind(this))
  46. this._state = Hot.State.Check
  47. // 下载version.manifest,进行版本比对
  48. this._assetsMgr.checkUpdate()
  49. return true
  50. }
  51. hotUpdate() {
  52. if (!this._assetsMgr) {
  53. Log.warn('请先初始化')
  54. return
  55. }
  56. this._assetsMgr.setEventCallback(this._hotUpdateCallBack.bind(this))
  57. this._state = Hot.State.Update
  58. this._assetsMgr.update()
  59. }
  60. _checkUpdateCb(event) {
  61. let code = event.getEventCode()
  62. console.log('checkUpdate Code: ' + code)
  63. switch (code) {
  64. case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
  65. case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
  66. case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
  67. this._onUpdateFailed(code)
  68. break
  69. case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
  70. console.log('已经和远程版本一致,无须更新')
  71. this._options.OnNoNeedToUpdate && this._options.OnNoNeedToUpdate(code)
  72. break
  73. case jsb.EventAssetsManager.NEW_VERSION_FOUND:
  74. console.log('发现新版本,请更新')
  75. this._options.OnNeedToUpdate && this._options.OnNeedToUpdate(code)
  76. break
  77. default:
  78. break
  79. }
  80. }
  81. _hotUpdateCallBack(event: jsb.EventAssetsManager) {
  82. let code = event.getEventCode()
  83. console.log(`hotUpdate Code: ${code}`)
  84. switch (code) {
  85. case jsb.EventAssetsManager.UPDATE_PROGRESSION:
  86. console.log('更新中...')
  87. if (this._state === Hot.State.Update) {
  88. this._options.OnUpdateProgress && this._options.OnUpdateProgress(event)
  89. } else {
  90. // 检查状态下,不回调更新进度
  91. }
  92. break
  93. case jsb.EventAssetsManager.UPDATE_FINISHED:
  94. console.log('更新成功')
  95. this._onUpdateFinished()
  96. break
  97. case jsb.EventAssetsManager.ASSET_UPDATED:
  98. // 不予理会的消息事件
  99. break
  100. default:
  101. this._onUpdateFailed(code)
  102. break
  103. }
  104. }
  105. _onUpdateFailed(code) {
  106. this._assetsMgr.setEventCallback(null)
  107. this._options.OnUpdateFailed && this._options.OnUpdateFailed(code)
  108. }
  109. // 更新完成
  110. _onUpdateFinished() {
  111. this._assetsMgr.setEventCallback(null)
  112. let searchPaths = jsb.fileUtils.getSearchPaths()
  113. let newPaths = this._assetsMgr.getLocalManifest().getSearchPaths()
  114. console.log('[HotUpdate] 搜索路径: ' + JSON.stringify(newPaths))
  115. Array.prototype.unshift(searchPaths, newPaths)
  116. cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths))
  117. jsb.fileUtils.setSearchPaths(searchPaths)
  118. this._options.OnUpdateSucceed && this._options.OnUpdateSucceed()
  119. }
  120. showSearchPath() {
  121. console.log('========================搜索路径========================')
  122. let searchPaths = jsb.fileUtils.getSearchPaths()
  123. for (let i = 0; i < searchPaths.length; i++) {
  124. console.log('[' + i + ']: ' + searchPaths[i])
  125. }
  126. console.log('======================================================')
  127. }
  128. // ------------------------------初始化------------------------------
  129. init(manifest: cc.Asset, opt: HotOptions) {
  130. if (!cc.sys.isNative) {
  131. return
  132. }
  133. if (!opt.check()) {
  134. return
  135. }
  136. this._options = opt
  137. if (this._assetsMgr) {
  138. return
  139. }
  140. this.showSearchPath()
  141. let url = manifest.nativeUrl
  142. // if (cc.loader.md5Pipe) {
  143. // url = cc.loader.md5Pipe.transformURL(url)
  144. // }
  145. let storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'remote-asset'
  146. this._assetsMgr = new jsb.AssetsManager(url, storagePath, (versionA, versionB) => {
  147. // 比较版本
  148. console.log('客户端版本: ' + versionA + ', 当前最新版本: ' + versionB)
  149. this._options.OnVersionInfo({local: versionA, server: versionB})
  150. let vA = versionA.split('.')
  151. let vB = versionB.split('.')
  152. for (let i = 0; i < vA.length; ++i) {
  153. let a = parseInt(vA[i])
  154. let b = parseInt(vB[i] || '0')
  155. if (a == b) {
  156. continue
  157. } else {
  158. return a - b
  159. }
  160. }
  161. if (vB.length > vA.length) {
  162. return -1
  163. } else {
  164. return 0
  165. }
  166. })
  167. this._assetsMgr.setVerifyCallback((assetsFullPath, asset) => {
  168. let {compressed, md5, path, size} = asset
  169. if (compressed) {
  170. return true
  171. } else {
  172. return true
  173. }
  174. })
  175. if (cc.sys.os === cc.sys.OS_ANDROID) {
  176. // 安卓手机设置 最大并发任务数量限制为2
  177. // this._assetsMgr.setMaxConcurrentTask(10);
  178. }
  179. let localManifest = this._assetsMgr.getLocalManifest()
  180. console.log('[HotUpdate] 热更新资源存放路径: ' + storagePath)
  181. console.log('[HotUpdate] 本地manifest路径: ' + url)
  182. console.log('[HotUpdate] local packageUrl: ' + localManifest.getPackageUrl())
  183. console.log('[HotUpdate] project.manifest remote url: ' + localManifest.getManifestFileUrl())
  184. console.log('[HotUpdate] version.manifest remote url: ' + localManifest.getVersionFileUrl())
  185. }
  186. }
  187. let hotInstance = new Hot()
  188. export default hotInstance