zoukankan      html  css  js  c++  java
  • 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));}
  • 相关阅读:
    罗振宇 知识就是力量之怎样做一个不冲动的人
    C++中stl的map
    stl中顺序性容器,关联容器两者粗略解释
    stl之容器、迭代器、算法几者之间的关系
    mysql技术内幕之常规使用
    essential c++ 第一章 array及vector相关使用
    由函数clock想到的
    编程获得CPU的主频
    Markdown 基本语法
    Future FutrueTask Callable类源码说明以及原理使用
  • 原文地址:https://www.cnblogs.com/pixs-union/p/9435882.html
Copyright © 2011-2022 走看看