Cocos Creator 热更新文件MD5计算和需要注意的问题

Creator的热更新使用jsb。热更新基本按照 http://docs.cocos.com/creator/manual/zh/advanced-topics/hot-update.html?h=%E7%83%AD%E6%9B%B4%E6%96%B0这个官方教程,

以及https://github.com/cocos-creator/tutorial-hot-update这个官方示例就行。但是,有一些地方没有提及,这会导致热更出现的问题。

1.自己保存热更目录到localstorage,进入时先读取这个目录,然后设置成资源查找目录。

//1.在资源更新完毕后,重启的时候加入以下处理
var searchPaths = jsb.fileUtils.getSearchPaths();
var newPaths = this._am.getLocalManifest().getSearchPaths();
for(let i = 0;i<newPaths.length;i++){
   if(searchPaths.indexOf(newPaths[i]) == -1){
      Array.prototype.unshift(searchPaths, newPaths[i]);
   }
}
jsb.fileUtils.setSearchPaths(searchPaths);
cc.sys.localStorage.setItem(‘HotUpdateSearchPaths‘, JSON.stringify(searchPaths));

//重启

cc.audioEngine.stopAll();

cc.game.restart();

//2.在main.js(build-templates/jsb-default/main.js)里,cc.game.run(option, onStart);之前 读取我们记录的HotUpdateSearchPaths,然后设置sarchPaths

var searchPaths = jsb.fileUtils.getSearchPaths();
var storePath = cc.sys.localStorage.getItem(‘HotUpdateSearchPaths‘);
storePath = JSON.parse(storePath);
storePath && jsb.fileUtils.setSearchPaths(storePath);

2.在热更模块中

this._am.setVerifyCallback(this._verifyFileHandle.bind(this));可以设置1个文件下载完成后,验证的函数。返回true就标识通过验证,该文件才标识更新成功。

但是文档和示例没有说明如何在js里计算文件md5。除此之外官方提供的用于遍历文件,计算文件md5然后,产生project.manifest、version.manifest 的nodejs脚本version_generator.js在计算文件md5时有一处问题。

md5 = crypto.createHash(‘md5‘).update(fs.readFileSync(subpath,"binary")).digest(‘hex‘);
这里fs.readFileSycn(subpath,"binary")返回的并非二进制类型,而是String。这会导致非文本文件md5计算错误。如果写入到manifest的文件md5是错误的,你下载文件后,计算md5作比较当然就很难匹配上了。除此之外,我们在jsb里只能使用:
 1.jsb.fileUtils.getStringFromFile(filePath);
 2.jsb.fileUtils.getDataFromFile(filePath);

 获取文件内容。getStringFromFile无法获取非文本文件内容。所以我们只能使用getDataFromFile获取文件二进制数据,它在js层面的视图类型是Uint8Array和nodejs readFileSync(subpath)一致。

3.前端js计算文件md5

1).改造version_generator.js

md5 = crypto.createHash(‘md5‘).update(fs.readFileSync(subpath,"binary")).digest(‘hex‘);

md5 = crypto.createHash(‘md5‘).update(fs.readFileSync(subpath)).digest(‘hex‘);

2)改造引擎自带的jsb_runtime_md5.js 它用js实现了byteArray md5的计算(大家可以在构建后搜索一下这文件,然后拷贝放到自己的js层工程里来)。但是这个还不能用,我们要稍微改造它。改造后的文件。

/**
 * from jsb_runtime_md5.js
 * @param {} data
 */
module.exports = function(data){
    // for test/debug
    function fflog(msg) {
        try {
            console.log(msg);
        } catch(e) {}
    }

    // convert number to (unsigned) 32 bit hex, zero filled string
    function to_zerofilled_hex(n) {
        var t1 = (n >>> 24).toString(16);
        var t2 = (n & 0x00FFFFFF).toString(16);
        return "00".substr(0, 2 - t1.length) + t1 +
            "000000".substr(0, 6 - t2.length) + t2;
    }

    // convert a 64 bit unsigned number to array of bytes. Little endian
    function int64_to_bytes(num) {
        var retval = [];
        for (var i = 0; i < 8; i++) {
            retval.push(num & 0xFF);
            num = num >>> 8;
        }
        return retval;
    }

    //  32 bit left-rotation
    function rol(num, places) {
        return ((num << places) & 0xFFFFFFFF) | (num >>> (32 - places));
    }

    // The 4 MD5 functions
    function fF(b, c, d) {
        return (b & c) | (~b & d);
    }

    function fG(b, c, d) {
        return (d & b) | (~d & c);
    }

    function fH(b, c, d) {
        return b ^ c ^ d;
    }

    function fI(b, c, d) {
        return c ^ (b | ~d);
    }

    // pick 4 bytes at specified offset. Little-endian is assumed
    function bytes_to_int32(arr, off) {
        return (arr[off + 3] << 24) | (arr[off + 2] << 16) | (arr[off + 1] << 8) | (arr[off]);
    }
    // convert the 4 32-bit buffers to a 128 bit hex string. (Little-endian is assumed)
    function int128le_to_hex(a, b, c, d) {
        var ra = "";
        var t = 0;
        var ta = 0;
        for (var i = 3; i >= 0; i--) {
            ta = arguments[i];
            t = (ta & 0xFF);
            ta = ta >>> 8;
            t = t << 8;
            t = t | (ta & 0xFF);
            ta = ta >>> 8;
            t = t << 8;
            t = t | (ta & 0xFF);
            ta = ta >>> 8;
            t = t << 8;
            t = t | ta;
            ra = ra + to_zerofilled_hex(t);
        }
        return ra;
    }

    // check input data type and perform conversions if needed

    if (!data instanceof Uint8Array){
        fflog("input data type mismatch only support Uint8Array");
        return null;
    }
    var databytes = [];
    for(var i = 0; i < data.byteLength;i++){
        databytes.push(data[i]);
    }

    // save original length
    var org_len = databytes.length;

    // first append the "1" + 7x "0"
    databytes.push(0x80);

    // determine required amount of padding
    var tail = databytes.length % 64;
    // no room for msg length?
    if (tail > 56) {
        // pad to next 512 bit block
        for (var i = 0; i < (64 - tail); i++) {
            databytes.push(0x0);
        }
        tail = databytes.length % 64;
    }
    for (i = 0; i < (56 - tail); i++) {
        databytes.push(0x0);
    }
    // message length in bits mod 512 should now be 448
    // append 64 bit, little-endian original msg length (in *bits*!)
    databytes = databytes.concat(int64_to_bytes(org_len * 8));

    // initialize 4x32 bit state
    var h0 = 0x67452301;
    var h1 = 0xEFCDAB89;
    var h2 = 0x98BADCFE;
    var h3 = 0x10325476;

    // temp buffers
    var a = 0,
        b = 0,
        c = 0,
        d = 0;

    function _add(n1, n2) {
        return 0x0FFFFFFFF & (n1 + n2)
    }

    // function update partial state for each run
    var updateRun = function(nf, sin32, dw32, b32) {
        var temp = d;
        d = c;
        c = b;
        //b = b + rol(a + (nf + (sin32 + dw32)), b32);
        b = _add(b,
            rol(
                _add(a,
                    _add(nf, _add(sin32, dw32))
                ), b32
            )
        );
        a = temp;
    };

    // Digest message
    for (i = 0; i < databytes.length / 64; i++) {
        // initialize run
        a = h0;
        b = h1;
        c = h2;
        d = h3;

        var ptr = i * 64;

        // do 64 runs
        updateRun(fF(b, c, d), 0xd76aa478, bytes_to_int32(databytes, ptr), 7);
        updateRun(fF(b, c, d), 0xe8c7b756, bytes_to_int32(databytes, ptr + 4), 12);
        updateRun(fF(b, c, d), 0x242070db, bytes_to_int32(databytes, ptr + 8), 17);
        updateRun(fF(b, c, d), 0xc1bdceee, bytes_to_int32(databytes, ptr + 12), 22);
        updateRun(fF(b, c, d), 0xf57c0faf, bytes_to_int32(databytes, ptr + 16), 7);
        updateRun(fF(b, c, d), 0x4787c62a, bytes_to_int32(databytes, ptr + 20), 12);
        updateRun(fF(b, c, d), 0xa8304613, bytes_to_int32(databytes, ptr + 24), 17);
        updateRun(fF(b, c, d), 0xfd469501, bytes_to_int32(databytes, ptr + 28), 22);
        updateRun(fF(b, c, d), 0x698098d8, bytes_to_int32(databytes, ptr + 32), 7);
        updateRun(fF(b, c, d), 0x8b44f7af, bytes_to_int32(databytes, ptr + 36), 12);
        updateRun(fF(b, c, d), 0xffff5bb1, bytes_to_int32(databytes, ptr + 40), 17);
        updateRun(fF(b, c, d), 0x895cd7be, bytes_to_int32(databytes, ptr + 44), 22);
        updateRun(fF(b, c, d), 0x6b901122, bytes_to_int32(databytes, ptr + 48), 7);
        updateRun(fF(b, c, d), 0xfd987193, bytes_to_int32(databytes, ptr + 52), 12);
        updateRun(fF(b, c, d), 0xa679438e, bytes_to_int32(databytes, ptr + 56), 17);
        updateRun(fF(b, c, d), 0x49b40821, bytes_to_int32(databytes, ptr + 60), 22);
        updateRun(fG(b, c, d), 0xf61e2562, bytes_to_int32(databytes, ptr + 4), 5);
        updateRun(fG(b, c, d), 0xc040b340, bytes_to_int32(databytes, ptr + 24), 9);
        updateRun(fG(b, c, d), 0x265e5a51, bytes_to_int32(databytes, ptr + 44), 14);
        updateRun(fG(b, c, d), 0xe9b6c7aa, bytes_to_int32(databytes, ptr), 20);
        updateRun(fG(b, c, d), 0xd62f105d, bytes_to_int32(databytes, ptr + 20), 5);
        updateRun(fG(b, c, d), 0x2441453, bytes_to_int32(databytes, ptr + 40), 9);
        updateRun(fG(b, c, d), 0xd8a1e681, bytes_to_int32(databytes, ptr + 60), 14);
        updateRun(fG(b, c, d), 0xe7d3fbc8, bytes_to_int32(databytes, ptr + 16), 20);
        updateRun(fG(b, c, d), 0x21e1cde6, bytes_to_int32(databytes, ptr + 36), 5);
        updateRun(fG(b, c, d), 0xc33707d6, bytes_to_int32(databytes, ptr + 56), 9);
        updateRun(fG(b, c, d), 0xf4d50d87, bytes_to_int32(databytes, ptr + 12), 14);
        updateRun(fG(b, c, d), 0x455a14ed, bytes_to_int32(databytes, ptr + 32), 20);
        updateRun(fG(b, c, d), 0xa9e3e905, bytes_to_int32(databytes, ptr + 52), 5);
        updateRun(fG(b, c, d), 0xfcefa3f8, bytes_to_int32(databytes, ptr + 8), 9);
        updateRun(fG(b, c, d), 0x676f02d9, bytes_to_int32(databytes, ptr + 28), 14);
        updateRun(fG(b, c, d), 0x8d2a4c8a, bytes_to_int32(databytes, ptr + 48), 20);
        updateRun(fH(b, c, d), 0xfffa3942, bytes_to_int32(databytes, ptr + 20), 4);
        updateRun(fH(b, c, d), 0x8771f681, bytes_to_int32(databytes, ptr + 32), 11);
        updateRun(fH(b, c, d), 0x6d9d6122, bytes_to_int32(databytes, ptr + 44), 16);
        updateRun(fH(b, c, d), 0xfde5380c, bytes_to_int32(databytes, ptr + 56), 23);
        updateRun(fH(b, c, d), 0xa4beea44, bytes_to_int32(databytes, ptr + 4), 4);
        updateRun(fH(b, c, d), 0x4bdecfa9, bytes_to_int32(databytes, ptr + 16), 11);
        updateRun(fH(b, c, d), 0xf6bb4b60, bytes_to_int32(databytes, ptr + 28), 16);
        updateRun(fH(b, c, d), 0xbebfbc70, bytes_to_int32(databytes, ptr + 40), 23);
        updateRun(fH(b, c, d), 0x289b7ec6, bytes_to_int32(databytes, ptr + 52), 4);
        updateRun(fH(b, c, d), 0xeaa127fa, bytes_to_int32(databytes, ptr), 11);
        updateRun(fH(b, c, d), 0xd4ef3085, bytes_to_int32(databytes, ptr + 12), 16);
        updateRun(fH(b, c, d), 0x4881d05, bytes_to_int32(databytes, ptr + 24), 23);
        updateRun(fH(b, c, d), 0xd9d4d039, bytes_to_int32(databytes, ptr + 36), 4);
        updateRun(fH(b, c, d), 0xe6db99e5, bytes_to_int32(databytes, ptr + 48), 11);
        updateRun(fH(b, c, d), 0x1fa27cf8, bytes_to_int32(databytes, ptr + 60), 16);
        updateRun(fH(b, c, d), 0xc4ac5665, bytes_to_int32(databytes, ptr + 8), 23);
        updateRun(fI(b, c, d), 0xf4292244, bytes_to_int32(databytes, ptr), 6);
        updateRun(fI(b, c, d), 0x432aff97, bytes_to_int32(databytes, ptr + 28), 10);
        updateRun(fI(b, c, d), 0xab9423a7, bytes_to_int32(databytes, ptr + 56), 15);
        updateRun(fI(b, c, d), 0xfc93a039, bytes_to_int32(databytes, ptr + 20), 21);
        updateRun(fI(b, c, d), 0x655b59c3, bytes_to_int32(databytes, ptr + 48), 6);
        updateRun(fI(b, c, d), 0x8f0ccc92, bytes_to_int32(databytes, ptr + 12), 10);
        updateRun(fI(b, c, d), 0xffeff47d, bytes_to_int32(databytes, ptr + 40), 15);
        updateRun(fI(b, c, d), 0x85845dd1, bytes_to_int32(databytes, ptr + 4), 21);
        updateRun(fI(b, c, d), 0x6fa87e4f, bytes_to_int32(databytes, ptr + 32), 6);
        updateRun(fI(b, c, d), 0xfe2ce6e0, bytes_to_int32(databytes, ptr + 60), 10);
        updateRun(fI(b, c, d), 0xa3014314, bytes_to_int32(databytes, ptr + 24), 15);
        updateRun(fI(b, c, d), 0x4e0811a1, bytes_to_int32(databytes, ptr + 52), 21);
        updateRun(fI(b, c, d), 0xf7537e82, bytes_to_int32(databytes, ptr + 16), 6);
        updateRun(fI(b, c, d), 0xbd3af235, bytes_to_int32(databytes, ptr + 44), 10);
        updateRun(fI(b, c, d), 0x2ad7d2bb, bytes_to_int32(databytes, ptr + 8), 15);
        updateRun(fI(b, c, d), 0xeb86d391, bytes_to_int32(databytes, ptr + 36), 21);

        // update buffers
        h0 = _add(h0, a);
        h1 = _add(h1, b);
        h2 = _add(h2, c);
        h3 = _add(h3, d);
    }
    // Done! Convert buffers to 128 bit (LE)
    return int128le_to_hex(h3, h2, h1, h0).toLowerCase();
};  

这里我把它改造成了只接受Uint8Array数据的格式。它原先只能计算字符串的md5码。

3)脚本里的使用方式

//引入我们的md5模块const MD5 = require("jsb_runtime_md5"); 
    /**
     * 指定文件验证函数
     * @param path 下载的文件的本地路径
     * @param asset 下载的资源
     */
    _verifyFileHandle:function(path, asset){
        //服务器上manifest里对该项资源配置的Md5码
        //asset.md5
        //服务器端的相对路径
        //asset.path
        //是否为压缩文件
        //asset.compressed
        //文件尺寸
        //asset.size
        //下载状态 包含 UNSTARTED、DOWNLOADING、SUCCESSED、UNMARKED
        //asset.downloadState
        var resMD5 = this.calMD5OfFile(path);
        return asset.md5 == resMD5;
    },

  calMD5OfFile:function(filePath){return MD5(jsb.fileUtils.getDataFromFile(filePath));}

原文地址:https://www.cnblogs.com/pixs-union/p/9435882.html

时间: 2024-10-27 12:57:48

Cocos Creator 热更新文件MD5计算和需要注意的问题的相关文章

Cocos Creator热更新

一,添加热更新需要的文件 1. 在项目根目录添加 version_generator.js 文件   version_generator.js 内容如下: /** * 此模块用于热更新工程清单文件的生成 */ var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var manifest = { //服务器上资源文件存放路径(src,res的路径) packageUrl: 'http

(原创)cocos lua 热更新从零开始(一)最简单demo

开发环境:WIN7 + cocos2dx 3.10 lua版本 0.学习这篇内容的基础是你要会创建并运行一个cocos lua项目 1.热更新的思想所谓的热更新,就是在线更新代码和资源.热更新的过程首先,客户端向服务器发送请求,服务器告诉客户端,没更新啦,你是最新的啦,那就直接跳过喽.但如果是告诉你有更新,那就要告诉我哪些需要更新对吧,你可能需要更新的东西,放在一个文件里,一并发送给客户端,客户端拿到这个文件,就一个一个去向服务器要,最后把要更新的内容都下载到本地了. 2.热更新用到的类:Ass

Unity热更新文件的服务器部署(IIS)

1.VS新建一个"ASP.NET空网站" 工程结构如下 2.添加一个一般处理程序用于处理游戏的登录请求Login.ashx,以及添加一个网站的主页index.html(可以不添加,仅仅为了测试网站是否连通) 这里的登录请求我就简单写了,仅仅为了测试 主页index.html也只是仅仅展示一行文字“Hello MyFrameWork!” 3.添加一个文件夹,用于存放自己的assetbundle 4.发布网站 右键先点击生成网站,生成成功之后,再点击发布Web应用 再弹出的窗体上,点击自定

Cocos Creator大厅+子游戏模式

一.前言 根据上一篇(Cocos Creator热更新),可以看出以下几点: build-default目录下的main.js,为cocos creator项目的入口: 热更新一文中,放置在服务器上的,仅有资源,脚本,配置等,没有入口程序,因此本文中,我们需要创造一个入口程序. 还是解释一下什么叫大厅+子游戏模式:   1. 将大厅单独作为一个完整的项目,不同的子游戏,则为不同的项目   2. 然后要实现不同项目之间的互调,即大厅调子游戏,或者子游戏调大厅   3. 资源共享,共用的资源放在大厅

Cocos Creator—定制H5游戏首页loading界面

Cocos Creator从1.0版本发布到现在也有一年多了,按理说一些常见的问题网上都有解决方案,例如"如何自定义首页加载进度条界面"这种普遍需求,应该所有人都会遇到的,因此也有完善的解决方案才对.我在网上搜了一些文章,虽然也有讨论的帖子,但是方案都不尽人意.因此只能再次自己动手丰衣足食了,在此我总结一下我的思路和策略,分享给大家,希望后来的人少走弯路,另外这里的方案只针对H5游戏发布,其他平台可以借鉴思路自己实现. 首页加载的loading界面,官网的文档并没有提及,我是通过构建发

cocos2dx 3.1.1 在线热更新 自动更新(使用AssetsManager更新游戏资源包)

为什么要在线更新资源和脚本文件? 简单概括,如果你的游戏项目已经在google play 或Apple Store 等平台上架了,那么当你项目需要做一些活动或者修改前端的一些代码等那么你需要重新提交一个新版本给平台.但是平台审核和具体的上架时间是个不确定的.具体什么时候能上架,主要由具体的平台决定. 如果游戏项目是使用脚本语言进行编写的(如lua.js),那么一旦需要更新,则可以通过从服务器下载最新的脚本和资源,从而跳过平台直接实现在线更新.(有些平台是禁止在线更新资源方式的,但是你懂得) 闲话

微端热更新

热更新一般需要包含以下东西: 1.URL1:游戏版本配置文件地址 2.URL2:所有资源的MD5配置文件地址 问题 如果将热更新分为强更和弱更(静默更新),以上的更新策略将会不支持静默更新. 新策略 在下载资源到缓冲区后添加一步是否同步文件.如果直接同步文件则为强更,如果不直接同步文件则为静默更新.在下一次进入游戏的时候判断是否有文件未同步–先同步再检查热更新. ++++++++++++++=====================================================

ionic cordova 热更新(引用自www.zyyapp.com/post/116.html)

上篇文章cordova 把html打包成安卓应用 http://www.zyyapp.com/post/115.html cordova 热更新是一个大坑,我看了一天一夜才明白.网上的教程都没说到重点,他们只说了在本地调试,没说发布到自己的服务器,只有一篇说了但是也不详细. 下边就是没有坑的教程,包你顺溜的走完流程. 打开命令提示符 进入工程目录,如果你只能在node.js command prompt 中运行cordova命令,那是因为你没有在系统变量path中添加node.js的路径. 添加

Cocos Creator—如何给资源打MD5版本号

Cocos Creator 是Cocos最新一代的游戏开发者工具,基于 Cocos2d-x,组件化,脚本化,数据驱动,跨平台发布.Cocos Creator的开发思路已经逐步跟Unity 3D靠拢,写起来也更方便快捷,开发效率更高. 但既然是新东西,免不了各种坑.其中在发布Web Mobile平台上,就有各种小问题,例如给资源加上md5版本号,Cocos Creator就不支持.从16年底开发组就说要支持MD5 Cache,等了大半年,新的1.6内测版本终于增加了MD5 Cache的功能,但效果