25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

466 satır
14 KiB

  1. require("preload.PluginPatcher")
  2. --[[
  3. 更新流程
  4. 1、获取服务器信息
  5. 2、更新资源
  6. 4.1 如果无需更新,则跳过此步骤
  7. 4.2 下载差分包并解压
  8. 3、如果是android,先检查APK更新。
  9. 2.1 如果无需更新,则跳过此步骤
  10. 2.2 下载差分包
  11. 2.3 合并新的APK
  12. 2.4 安装新的APK
  13. 4、检查强更版本号。
  14. 3.1 如果无需更新,则跳过此步骤
  15. 3.2 如果需要更新,则弹出更新提示
  16. 5、检查文件完整性
  17. 6、完成更新
  18. 6.1 如果本次没有更新资源,则完成更新
  19. 6.2 如果本次有更新内容,则提示玩家重启游戏。否则直接进入游戏
  20. --]]
  21. local AutoUpdater = {};
  22. AutoUpdater.__index = AutoUpdater;
  23. local writablePath = cc.FileUtils:getInstance():getWritablePath()
  24. local updateConfirmSize = 5 * 1024 * 1024
  25. local tempDir = os.date("%Y%m%d%H%M", os.time());
  26. local tempFile="tempFile.zip"
  27. local zipFileDir = writablePath .. tempDir .. '/'
  28. local zipFilePath = zipFileDir .. tempFile;
  29. -- 创建新对象
  30. function AutoUpdater:new(...)
  31. local instance = {};
  32. setmetatable(instance , AutoUpdater);
  33. instance:ctor(...);
  34. return instance;
  35. end
  36. function AutoUpdater:ctor(romSetting, mainScene, onFinsishCallback)
  37. -- 保存全局配置
  38. self.romSetting = romSetting
  39. self.onFinsishCallback = onFinsishCallback
  40. self.Packages={}
  41. self.OldFiles={}
  42. self.NewFiles={}
  43. -- 渲染视图
  44. self.View = require("preload.AutoUpdate.AutoUpdaterView"):new(self, mainScene)
  45. -- 是否提示过APK更新
  46. self.isShowApkPatch = false;
  47. --是否清理过文件
  48. self.IsCleanFile = false
  49. --是否更新过程出现问题
  50. self.IsError=false
  51. -- 是否更新了资源
  52. self.isUpdateRes = false;
  53. -- 标记本次更新是否已经成功获取到配置信息了
  54. self.isGetServerConfigSuccessed = false
  55. end
  56. function AutoUpdater:doNext()
  57. logD("AutoUpdater:doNext()");
  58. if #self.execQueue > 0 then
  59. local execFunc = self.execQueue[1]
  60. table.remove(self.execQueue, 1)
  61. if execFunc then
  62. execFunc()
  63. end
  64. else
  65. self:onUpdateFinished()
  66. end
  67. end
  68. function AutoUpdater:startUpdate()
  69. logD("AutoUpdater:startUpdate()");
  70. self.execQueue = {}
  71. table.insert(self.execQueue, handler(self, self.getServerConfigs))
  72. table.insert(self.execQueue, handler(self, self.updateRes))
  73. table.insert(self.execQueue, handler(self, self.updateApk))
  74. table.insert(self.execQueue, handler(self, self.updateForce ))
  75. table.insert(self.execQueue, handler(self, self.checkFilesExist))
  76. self:doNext()
  77. end
  78. function AutoUpdater:getServerConfigs()
  79. logD("AutoUpdater:getServerConfigs()");
  80. self.isGetServerConfigSuccessed = false
  81. local function onEndGetServerConfig(isSuccessed)
  82. logD("AutoUpdater:onEndGetServerConfig(), isSuccessed = ", tostring(isSuccessed));
  83. if isSuccessed then
  84. if not self.isGetServerConfigSuccessed then
  85. self.isGetServerConfigSuccessed = true
  86. self:doNext()
  87. else
  88. logD("AutoUpdater:getServerConfigs(), 重复收到服务器的配置数据,本次不处理");
  89. end
  90. else
  91. self:dispatchEvent("error", "初始化失败,请更换网络后重试")
  92. end
  93. end
  94. if isIOSPlatform() then
  95. checkNetWorkPermission(function()
  96. getServerConfigs(onEndGetServerConfig, true)
  97. end)
  98. else
  99. getServerConfigs(onEndGetServerConfig, true)
  100. end
  101. end
  102. -- 更新资源
  103. function AutoUpdater:updateRes()
  104. logD("AutoUpdater:updateStart() 检查资源更新")
  105. if PhpSetting.update.url=="" or PhpSetting.update.md5=="" then
  106. local ver = loadVersion()
  107. if tonumber(ver) ~= tonumber(PhpSetting.update.ver) and not self.IsCleanFile then
  108. logD("AutoUpdater:updateStart() 找不到版本,开始清理数据")
  109. self:ClearDatingCache()
  110. self:startUpdate()
  111. self.IsCleanFile = true
  112. else
  113. logD("AutoUpdater:updateStart() 版本一致,无需更新")
  114. self:doNext()
  115. end
  116. return
  117. end
  118. -- 有文件需要更新
  119. logD("AutoUpdater:updateStart() 有文件需要更新")
  120. self.isUpdateRes = true;
  121. self.DownloadedFileSize=tonumber(PhpSetting.update.size)
  122. local function onFinishDownZip()
  123. logD("AutoUpdater:onFinishDownZip(), 下载差分包完成");
  124. local md5=cc.FileUtils:getInstance():md5File(zipFilePath)
  125. if md5~=PhpSetting.update.md5 then
  126. logD("AutoUpdater:onFinishDownZip(), 校验差分包失败, update.md5 = " .. PhpSetting.update.md5 );
  127. logD("AutoUpdater:onFinishDownZip(), 校验差分包失败, md5 = " .. md5 );
  128. os.remove(zipFilePath)
  129. self:dispatchEvent("error",PLN.FILE_CHECKSUM_FAILED)
  130. return
  131. end
  132. self:dispatchEvent("zip",{text=PLN.UPDATING_RES,percent=1})
  133. runDelayWithTime(function()
  134. local isZipSuccessed=cc.FileUtils:getInstance():decompress(zipFilePath)
  135. os.remove(zipFilePath)
  136. logD("AutoUpdater:onFinishDownZip(), 解压差分包完成" );
  137. if isZipSuccessed then
  138. local move_result = move_dir(zipFileDir, writablePath);
  139. if move_result then
  140. logD("AutoUpdater:onFinishDownZip() need restart");
  141. local function OnClickOk()
  142. cc.Application:getInstance():restart()
  143. end
  144. local tipsMessage = "更新完成,点击确认重启游戏"
  145. showTipsView(tipsMessage, OnClickOk, nil)
  146. else
  147. self:dispatchEvent("error",PLN.FILE_MOVE_FAILED)
  148. end
  149. else
  150. self:dispatchEvent("error",PLN.FILE_UNCOMPRESS_FAILED)
  151. end
  152. remove_dir(zipFileDir)
  153. end,0.01)
  154. end
  155. local function onState( state, msg )
  156. logD("AutoUpdater:updateRes() onState() :", state, msg)
  157. if state=="progress" then
  158. local percent = msg--self.DownloadedFileSize*msg / self.DownloadedFileSize;
  159. self:dispatchEvent("downloadFile" , {text = string.format(PLN.DOWNLOADING_FILE , self.DownloadedFileSize*percent / 1024 / 1024 , self.DownloadedFileSize / 1024 / 1024 , percent * 100) , percent = percent});
  160. elseif state=="successed" then
  161. local percent = 1
  162. self:dispatchEvent("downloadFile" , {text = string.format(PLN.DOWNLOADING_FILE , self.DownloadedFileSize*percent / 1024 / 1024 , self.DownloadedFileSize / 1024 / 1024 , percent * 100) , percent = percent});
  163. runDelayWithTime(function()
  164. onFinishDownZip()
  165. end,0.01)
  166. else
  167. self:dispatchEvent("error",PLN.DOWNLOAD_FILE_FAILED)
  168. end
  169. end
  170. if not cc.FileUtils:getInstance():isDirectoryExist(zipFileDir) then
  171. if not cc.FileUtils:getInstance():createDirectory(zipFileDir) then
  172. logD("AutoUpdater:updateStart() createDirectory failed :" .. zipFileDir)
  173. end
  174. end
  175. downloadFileByUrls2(PhpSetting.update.url, onState, zipFilePath)
  176. end
  177. -- 更新APK
  178. function AutoUpdater:updateApk()
  179. if self.isShowApkPatch then
  180. self:doNext()
  181. return
  182. end
  183. self.isShowApkPatch = true;
  184. logD("AutoUpdater:updateApk()")
  185. if isAndroidPlatform() and PhpSetting.apkupdate and PhpSetting.apkupdate.url ~= nil and PhpSetting.apkupdate.url ~= "" then
  186. local function installNewApk(apk_file)
  187. logD("AutoUpdater:installNewApk() apk_file = ", apk_file)
  188. patcherInstallApk(apk_file);
  189. end
  190. local function mergePatchToApk(patchFilePath)
  191. logD("AutoUpdater:mergePatchToApk() patchFilePath = ", patchFilePath)
  192. self:dispatchEvent("info","正在生成新的安装包")
  193. local patch_file = patchFilePath;
  194. local patch_md5 = PhpSetting.apkupdate.md5;
  195. local apk_file = writablePath .. PhpSetting.apkupdate.ver .. ".apk";
  196. local apk_md5 = PhpSetting.apkupdate.apkmd5
  197. local result = patcherMakeApk(patch_file, patch_md5, apk_file, apk_md5);
  198. logD("AutoUpdater:mergePatchToApk() result = ", result)
  199. if result then
  200. installNewApk(apk_file);
  201. else
  202. self:doNext()
  203. end
  204. end
  205. local function downloadPatch ()
  206. local totalSize = tonumber(PhpSetting.apkupdate.size)
  207. local currentSize = 0;
  208. self:dispatchProgress(currentSize, totalSize);
  209. local patchFilePath = writablePath .. PhpSetting.apkupdate.ver .. ".patch";
  210. logD("AutoUpdater:downloadPatch() patchFilePath = ", patchFilePath)
  211. local function onState( state, msg )
  212. logD("AutoUpdater:downloadPatch() onState() :", state, msg)
  213. if state=="progress" then
  214. local percent = msg
  215. currentSize = totalSize * percent;
  216. self:dispatchProgress(currentSize, totalSize);
  217. elseif state=="successed" then
  218. local percent = 1
  219. currentSize = totalSize
  220. self:dispatchProgress(currentSize, totalSize);
  221. runDelayWithTime(function()
  222. mergePatchToApk(patchFilePath)
  223. end,0.01)
  224. else
  225. self:dispatchEvent("error",PLN.DOWNLOAD_FILE_FAILED)
  226. -- 如果下载失败就直接进入下一步,检测强制更新
  227. self:checkUpdate();
  228. end
  229. end
  230. logD("AutoUpdater:downloadPatch() url = ", PhpSetting.apkupdate.url)
  231. downloadFileByUrls2(PhpSetting.apkupdate.url, onState, patchFilePath)
  232. end
  233. local function onClickOk()
  234. downloadPatch();
  235. end
  236. local function onClickCancel()
  237. self:doNext()
  238. end
  239. -- 提示信息
  240. local content = PhpSetting.apkupdate.content;
  241. if content == nil or content == "" then
  242. content = "发现有新的安装包可以使用,是否下载新的安装包?"
  243. end
  244. -- 是否可以取消更新
  245. if PhpSetting.apkupdate.update_type == 2 then
  246. onClickCancel = nil
  247. end
  248. -- 点击确定后是否关闭界面
  249. local closeWhenOk = true;
  250. require("preload.AutoUpdate.UpdateTipsView"):new(content, onClickOk, onClickCancel, closeWhenOk)
  251. return
  252. else
  253. self:doNext()
  254. end
  255. end
  256. -- 检查强更版本
  257. function AutoUpdater:updateForce()
  258. if PhpSetting and PhpSetting.force then
  259. -- 检查强制更新
  260. if tonumber(PhpSetting.force.isForce) > 0 then
  261. local title = "发现新版本"
  262. local content = PhpSetting.force.tips or ""
  263. local url = PhpSetting.force.url
  264. if not url or url == "" then
  265. url = self.romSetting.downloadUrl
  266. end
  267. if not url or url == "" then
  268. url = "https://www.baidu.com"
  269. end
  270. local function onClick(ret)
  271. logD("AutoUpdater:updateForce() onClick, url = ", tostring(url))
  272. if PluginDevice then
  273. PluginDevice:callVoid("openUrl", url)
  274. else
  275. logD("AutoUpdater:updateForce() PluginDevice is nil")
  276. end
  277. end
  278. require("preload.AutoUpdate.UpdateTipsView"):new(content, onClick )
  279. return
  280. end
  281. -- 检查提示更新
  282. if tonumber(PhpSetting.force.isTips) > 0 then
  283. local title = "发现新版本"
  284. local content = PhpSetting.force.tips or ""
  285. local url = PhpSetting.force.url
  286. if not url or url == "" then
  287. url = self.romSetting.downloadUrl
  288. end
  289. if not url or url == "" then
  290. url = "https://www.baidu.com"
  291. end
  292. local function onClickOk(ret)
  293. logD("AutoUpdater:updateForce() onClickOk, url = ", tostring(url))
  294. if PluginDevice then
  295. PluginDevice:callVoid("openUrl", url)
  296. else
  297. logD("AutoUpdater:updateForce() PluginDevice is nil")
  298. end
  299. end
  300. local function onClickCancel(ret)
  301. logD("AutoUpdater:updateForce() onClickCancel")
  302. self:doNext()
  303. end
  304. require("preload.AutoUpdate.UpdateTipsView"):new(content,onClickOk, onClickCancel)
  305. return
  306. end
  307. end
  308. self:doNext()
  309. end
  310. -- 检查文件是否完整
  311. function AutoUpdater:checkFilesExist()
  312. local files_list_file = self.romSetting.Platform .. "/files.txt"
  313. local ret, missing_files_list = checkFilesExist(files_list_file)
  314. if ret then
  315. logD("AutoUpdater:checkFilesExist(), 校验完成,未发现文件缺失");
  316. self:doNext();
  317. else
  318. logD("AutoUpdater:checkFilesExist(), 校验完成,发现有文件丢失");
  319. local function OnClickOk()
  320. self:ClearDatingCache()
  321. cc.Application:getInstance():restart()
  322. end
  323. local tipsMessage = "发现有文件丢失,点击确定开始修复"
  324. showTipsView(tipsMessage, OnClickOk, nil)
  325. end
  326. end
  327. -- 更新完成
  328. function AutoUpdater:onUpdateFinished()
  329. logD("AutoUpdater:onUpdateFinished()");
  330. self:dispatchEvent("finish", "更新完成!")
  331. if self.isUpdateRes then
  332. logD("AutoUpdater:onUpdateFinished() need restart");
  333. local function OnClickOk()
  334. cc.Application:getInstance():restart()
  335. end
  336. local tipsMessage = "更新完成,点击确认重启游戏"
  337. showTipsView(tipsMessage, OnClickOk, nil)
  338. else
  339. logD("AutoUpdater:onUpdateFinished() not need restart");
  340. if self.onFinsishCallback then
  341. self.onFinsishCallback()
  342. end
  343. self.View:onExit();
  344. end
  345. end
  346. -- 通知界面显示当前进度
  347. function AutoUpdater:dispatchProgress(currentSize, totalSize)
  348. local percent = currentSize / totalSize
  349. self:dispatchEvent("downloadFile" , {text = string.format(PLN.DOWNLOADING_FILE , currentSize / 1024 / 1024 , totalSize / 1024 / 1024 , percent * 100) , percent = percent});
  350. end
  351. -- 派发一个更新事件给外部侦听者
  352. function AutoUpdater:dispatchEvent(eventName , eventValue)
  353. logD("AutoUpdater:dispatchEvent()" , eventName , eventValue);
  354. --[[
  355. if eventName == "error" then
  356. self.IsError=true
  357. uploadErrorLogs("AutoUpdaterError");
  358. end
  359. --]]
  360. self.View:showProgress(eventName , eventValue);
  361. if eventName == "error" then
  362. local function OnClickOk()
  363. cc.Application:getInstance():restart()
  364. end
  365. -- 上报更新错误
  366. uploadLogs(GAME_ERROR_TYPE.UPDATEFAILED)
  367. -- 提示更新失败
  368. local tipsMessage = "出错了,点击确定重新开始更新"
  369. showTipsView(tipsMessage, OnClickOk, nil)
  370. end
  371. end
  372. -- 清理大厅的缓存文件
  373. function AutoUpdater:ClearDatingCache()
  374. logD("AutoUpdater:ClearDatingCache() 清理大厅的缓存文件")
  375. local corePath = writablePath.."core/"
  376. local datingRomFiles = writablePath..self.romSetting.Platform.."/romFiles/"
  377. local datingPreload = writablePath..self.romSetting.Platform.."/preload/"
  378. local datingScript = writablePath..self.romSetting.Platform.."/luaScript/"
  379. local datingRes = writablePath..self.romSetting.Platform.."/res/"
  380. cc.FileUtils:getInstance():removeDirectory(corePath)
  381. cc.FileUtils:getInstance():removeDirectory(datingRomFiles)
  382. cc.FileUtils:getInstance():removeDirectory(datingPreload)
  383. cc.FileUtils:getInstance():removeDirectory(datingScript)
  384. cc.FileUtils:getInstance():removeDirectory(datingRes)
  385. local filesListPath = writablePath..self.romSetting.Platform.."/files.txt"
  386. os.remove(filesListPath)
  387. cc.FileUtils:getInstance():purgeCachedEntries()
  388. --logD("删除UserConfig.xml")
  389. --os.remove(writablePath .. "UserConfig.xml")
  390. end
  391. return AutoUpdater;