热更新范例工程更新失败原因分析及临时补救措施

今天学习热更新功能,跑范例工程的时候,不知道是我使用方式不对还是服务器没配置好,遇到了一些问题。我把发现问题的过程分享出来,如果是引擎的问题,希望对@panda老师修复Bug有帮助。
###环境
Windows10+Creator 1.5.0 beta.2+Android 5.0+xampp默认配置的apache服务器
###问题

  1. 范例工程热更新至60%~70%(@1112979 发现在这个百分比断网重连,几乎必现黑屏,若无黑屏请清除应用数据后重试)左右将设备断网重连1~2次,会自动继续更新,但更新成功后游戏黑屏,强退再开仍然黑屏;
  2. 热更新期间若将设备断网重连多次(5次以上?),会无限提示"Update failed.",点重试更新或强退游戏再开仍然无法继续更新。
    ###分析
    黑屏问题估计是游戏启动时代码执行错误,不知道这种情况下怎么捕获错误,于是在main.js开头使用window.__errorHandler将错误信息上传至服务器:
// report.php
<?php
error_log(json_encode($_REQUEST));

重新打Android包运行后,服务器收到错误信息:

[06-May-2017 09:18:20 UTC] {"file":"\/data\/data\/org.cocos2d.tutorialhotupdate\/files\/blackjack-remote-asset\/src\/jsb_polyfill.js","line":"11353","error":"SyntaxError: missing : after property id"}

可以看到,是热更新的资源jsb_polyfill.js第11353行语法错误。打开范例工程的remote-assets/src/jsb_polyfill.js第11353行,结果没有发现语法错误的地方:


难道是热更新下载的jsb_polyfill.js跟远程的不一致?将设备里的/data/data/org.cocos2d.tutorialhotupdate/files/blackjack-remote-asset/src/jsb_polyfill.js复制出来后,验证了这一猜想:

11353行处,代码从头开始下载了!附jsb_polyfill.js代码开头(与上图11353行之后一模一样):

以及从设备中复制出来的jsb_polyfill.js(5793行、11353行、29123行三处都从头开始了):
jsb_polyfill.zip (379.5 KB)
并且/data/data/org.cocos2d.tutorialhotupdate/files/blackjack-remote-asset/src/下只有3个js文件,远程有5个,没有更新完全。
以上结果均为热更新提示成功、自动重启后黑屏,且/data/data/org.cocos2d.tutorialhotupdate/files/路径下没有blackjack-remote-asset_temp的情况
###结论
若热更新过程中设备断网重连,热更新可能在错误的情况下提示更新成功!且这个错误是不可逆的,因为设备本地已经认为这些资源下载完全了。
###补救

  1. 在main.js开头添加错误捕捉代码,若出错文件来自热更新目录,则删除热更新目录,重启游戏重新开始热更新:
  2. 若遇到无限Update failed,也可以在HotUpdate.js的case jsb.EventAssetsManager.UPDATE_FAILED:分支下跟上图一样删除热更新目录,重新开始热更新。
4赞

也提过几次这个问题,但是语言组织不好。。。希望大神的提问方式有大神专门解答一下,这种方法不是长久之计啊

其实你效验每个文件的MD5就可以了,但是官方生成的MD5,之前的版本有问题,我提过,不知道现在修改没有

这个计算MD5的方法是要自己写吗,检验出错之后要进行什么操作,
可以直接用这个assetsManager.downloadFailedAssets();?

对的,我也自己网上找了一个md5的算法,还有官方提供的manifest生成器有问题(老司机说的),所以这个文件也是需要修改的,我已经测试过没问题了,更新了几百个文件,大小都有。中途断开好多次也没有问题了

manifest生成器裡的md5問題已經修改過了

看Git的記錄就知道了

比如这个算法https://www.teakki.com/p/57dfb319d3a7507f975e8280

this._am.setVerifyCallback(function (path, asset) {
        var compressed = asset.compressed;
        var expectedMD5 = asset.md5;
        var relativePath = asset.path;
        var size = asset.size;
        if (compressed) {
            cc.log("Verification passed : ");
            return true;
        } else {
            var fileStr = jsb.fileUtils.getStringFromFile(path);
            var md5 = 计算md5方法(fileStr);
            if(md5 == asset.md5){
                 return true;
            }else{
                 return false;
            }
        }
    }
}

这样写可以吗,求指教啊

不错,这个有意义,可能还有个remote-asset_temp目录也要删除

谢谢大家的反馈

这个问题应该是 windows 上的断点续传出现问题了,@toddlxt 麻烦确认一下你的服务器支不支持 accept-ranges header,Android 版本修复过此问题,本来 curl 应该是支持的,估计之前其他人在重构 downloader 过程中忽略了

所以可以添加一条补救措施:在服务端开启断点续传的支持,就可以避免从头下载文件了

1赞

@panda
试了一下,apache是默认支持断点续传的。

好的,我检查一下是不是 curl 那边没有发送 content-range

这个问题最后是怎么解决的?
我这边默认src里面的5个.js文件找不到

setVerifyCallback,加上这个效验就OK了.

请问这点在哪个文件查看验证?我这边升级2.1.2的引擎似乎断点续传出问题了,一次更新完毕正常

同问、同问

mark,这个是个好东西