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));}

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

  1. cocos creator热更新教程

    1.下载HotUpdate热更新DEMO 2.在cocos creator中下载热更新插件,cocos creator版本要在1.7及以上版本 3.插件默认安装在C:\Users\Administra ...

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

    开发环境:WIN7 + cocos2dx 3.10 lua版本 0.学习这篇内容的基础是你要会创建并运行一个cocos lua项目 1.热更新的思想所谓的热更新,就是在线更新代码和资源.热更新的过程首 ...

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

    1.VS新建一个"ASP.NET空网站" 工程结构如下 最好设置.Net FrameWork版本为 V4.0或者V4.5版本的,因为我们的程序最后是要部署到阿里云的虚拟服务器上的, ...

  4. 【Quick 3.3】资源脚本加密及热更新(三)热更新模块

    [Quick 3.3]资源脚本加密及热更新(三)热更新模块 注:本文基于Quick-cocos2dx-3.3版本编写 一.介绍 lua相对于c++开发的优点之一是代码可以在运行的时候才加载,基于此我们 ...

  5. Cocos2d-js 热更新学习笔记

    转载至: http://blog.csdn.net/pt_xxj/article/details/68927705 为什么还要再写一篇关于cocos2d js热更新的笔记,最单纯的想法就是记录心得,另 ...

  6. 【转】: 《江湖X》开发笔谈 - 热更新框架

    前言 大家好,我们这期继续借着我们工作室正在运营的在线游戏<江湖X>来谈一下热更新机制以及我们的理解和解决方案.这里先简单的介绍一下热更新的概念,熟悉这部分的朋友可以跳过,直接看我们的方案 ...

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

    Cocos Creator从1.0版本发布到现在也有一年多了,按理说一些常见的问题网上都有解决方案,例如"如何自定义首页加载进度条界面"这种普遍需求,应该所有人都会遇到的,因此也有 ...

  8. nodejs五子棋online游戏开发视频教程,客户端cocos creator js

    开发的游戏是五子棋online,网络版的,服务端部分和客户端部分都在这个教程里面,可以看一下目录! 服务器nodejs游戏开发教程 使用Nodejs开发网络服务器 游戏服务端 ,cocos creat ...

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

    上篇文章cordova 把html打包成安卓应用 http://www.zyyapp.com/post/115.html cordova 热更新是一个大坑,我看了一天一夜才明白.网上的教程都没说到重点 ...

随机推荐

  1. netcore kafka操作

    安装使用: 1:下载nuget包 Confluent.Kafka librdkafka.redist System.Runtime.CompilerServices.Unsafe 基于.net实现ka ...

  2. Delphi GetDir 获取指定驱动器的当前路径名

    //获取指定驱动器的当前路径名 GetDirvardir: string;b: Byte;beginb := 0;GetDir(b,dir);ShowMessage(dir); // //第一个参数: ...

  3. bazel编译im2txt的问题

    问题: 原本可以正常运行的程序,出现找不到tensorflow的问题.打印出来sys.version和sys.path,发现python版本并不是conda环境的版本 (tensorflow) yua ...

  4. golang(08)接口介绍

    原文链接 http://www.limerence2017.com/2019/09/12/golang13/#more 接口简介 golang 中接口是常用的数据结构,接口可以实现like的功能.什么 ...

  5. js多元运算

    for(var i=1;i<=100;i++){ var f = i%3 == 0, b = i%5 == 0; if(f){ if(b){ console.log("FizzBuzz ...

  6. v8 google 下载及编译

    ubuntu环境下进行 参考文档: http://code.google.com/p/v8/wiki/BuildingWithGYP (一) 源码下载及编译 1, Google v8 官网:http: ...

  7. 为什么样本标准差要除以n-1?

    根据中心极限定理,我们可以用样本估计总体的平均值.那么,如果通过n个样本估计总体的标准差则需要除以n-1,这是为什么呢? 标准差是描述数据与平均值的偏离程度. 而因为样本的数据量比总体的数据量少,因此 ...

  8. git clone 报错 fatal: protocol '–https' is not supported 解决办法

    版本:git 2.22.0 系统:win7旗舰版 先把https去掉 再把https加上 神奇的事情出现了,这样就可以了. 很多人都说这样解决了,原因不知道. Administrator@BWE8QX ...

  9. rabbitmq五种消息模型整理

    目录 0. 配置项目 1. 基本消息模型 1.1 生产者发送消息 1.2 消费者获取消息(自动ACK) 1.3 消息确认机制(ACK) 1.4 消费者获取消息(手动ACK) 1.5 自动ACK存在的问 ...

  10. Ubuntu 系统安装 Docker

    安装 Docker CE 有多种方法,下面是最简单的通过Docker仓库的安装方法,其他方法参见官方文档. 设置仓库 刷新软件包 sudo apt-get update 安装必要的软件包 sudo a ...