全面讲解cocoscreator热更新(2.4.x)

环境相关

系统:mac

当前版本是cocoscreator 2.4.x,

语言是typescript

构建模版:link

发布路径: ./build

发布平台: andoid

资源服务器: ftp 或 nodejs

构建界面MD5选项:取消勾选md5选项(热更新不能勾选md5 cache,如果勾选md5,需要自己在原生层实现更新 main.js 文件,main.js 加载的时候会将热更新目录添加到文件搜索路径,如果这一步出现异常,最终运行会加载到包内的旧文件。)

本文用到demo:在公众号 亮亮同学TT。发送 热更 即可获得 源码和资源工程(帖子的图片总是挂掉,关键部分用代码代替了,另外公众号 也有本文,图文并貌,可以参考)

目录:

1,热更效果展示

2,热更流程介绍

3,热更涉及到的文件介绍

4,以白话的形式解释cocoscreator热更新

5,基础版实际操作

6,可版本回退版实际操作

7,动态地址热更实际操作

首先看一下热更新的效果

下面四张图分别是:

1,初始界面是有一只小飞机,版本是1.0.0

2,点击检查版本发现有新版本

3,点击热更按钮,更新为远程版本 小僵尸 替换掉了小飞机,版本号升到 1.0.2

4,再次点击检查热更,提示我们 现在已经跟新到最新版本。

然后我们在具体的了解一下cocoscreator的热更原理

cocoscreator的热更新仿照web网页的更新模式,大致如下:

1,服务器端保存最新版本的完整资源

2,客户端发送请求服务器端版本进行对比获得差异列表

3,从服务器下载所有新版本中改动的资源文件

4,用新资源覆盖旧缓存以及应用包内的文件

注意:
Cocos 的热更新机制通过直接比较最新版本和本地版本的差异来生成差异列表并更新。这样即可天然支持跨版本更新,比如本地版本为 A,远程版本是 C,则直接更新 A 和 C 之间的差异,并不需要生成 A 到 B 和 B 到 C 的更新包,依次更新。所以,在这种设计思路下,新版本的文件以离散的方式保存在服务端,更新时以文件为单位下载。

接着详细的了解cocoscreator热更流程

下面这张图 展示了cocoscreator的 热更流程

那么我们实现热更需要哪些操作呢?要修改哪些文件?要写哪些代码,注意哪些问题呢?

热更涉及到的文件介绍

(1)Manifest文件
Manifest格式文件是用来比较本地和远程资源差异的一种json格式,其中保存了版本信息,引擎版本信息等等,我们通过Manifest文件进行对比版本 判断是否需要热更新。

Manifest文件有两个 分别是 project.manifest 包含了所有的热更需要的信息如下

{
    "packageUrl" :          远程资源的本地缓存根路径
    "remoteVersionUrl" :    [可选项] 远程版本文件的路径,用来判断服务器端是否有新版本的资源
    "remoteManifestUrl" :   远程资源 Manifest 文件的路径,包含版本信息以及所有资源信息
    "version" :             资源的版本
    "engineVersion" :       引擎版本
    "assets" :              所有资源列表
        "key" :             资源的相对路径(相对于资源根目录)
        "md5" :             md5 值代表资源文件的版本信息
        "compressed" :      [可选项] 如果值为 true,文件被下载后会自动被解压,目前仅支持 zip 压缩格式
        "size" :            [可选项] 文件的字节尺寸,用于快速获取进度信息
    "searchPaths" :         需要添加到 FileUtils 中的搜索路径列表
}

另一个是version.manifest文件 只包含了少量的热更信息, 如版本信息等。结构如下:

{"packageUrl":远程资源的本地缓存路径,
"remoteManifestUrl":远程资源 Manifest 文件的路径,包含版本信息以及所有资源信息
"remoteVersionUrl":远程版本文件的路径,用来判断服务器端是否有新版本的资源
"version":版本信息
}

这两个文件由 version_generator.js生成。 安装nodejs 修改相关参数 cd 到当前version_generator.js目录。

运行node version_generator.js 即可生成

(2)assets 和 src 文件目录
在项目构建之前我们可以看到 assets文件夹中包含了 游戏的资源以及代码,这是构建之前的工程资源目录。当我们构建工程后。 我们会在biuld/jsb-link/下面看到 assets 和 src 两个文件夹。
assets是保存了构建后的资源,src是保存了构建后的脚本。

白话的形式解释cocoscreator热更新

cocoscreator热更新是对远程版本和本地版本的 版本号进行对比 cocoscreator认为 本地版本号小于远程版本号就需要进行热更,版本号如何而来呢? 是在 manifest文件里获取,我们把携带高版本号的 manifest文件和最新的构建资源放到远程服务器 ,同时本地的包内留有版本较低和旧的资源,当在需要检查热更的时候 ,cocoscretor会先初始化本地包内的manifest文件,同时创建指定目录的临时文件夹和缓存文件夹 比如缓存文件夹是plane,临时文件夹则为plane.temp。下载远程的version.manifest文件缓存到本地 ,获取版本号,进行比较,远程版本高,则下载 携带资源信息的project.manifest 文件到临时文件夹plane.temp下。接着对比本地project.manifest与从远程下载到临时文件夹中的project.manifest 资源列表 即 当中的assets表,然后生成差异列表。然后通过downloader进行下载差异列表中的文件到本地,如果有压缩文件解压缩。文件下载成功后,对下载的文件进行校验接着通知下载进度,保存下载进度,检查是否有失败的资源,如果没有 则 拷贝临时文件夹的所有内容到 设定的缓存目录,如果更新失败不拷贝临时资源到缓存目录,避免了污染原有的本地缓存资源。cocoscreator会使用manifest文件标示每个资源的状态(未开始,下载中,下载完成)如果热更中途网络中断,重新启动热更,cocoscreator会检查临时文件夹中是否有未完成的更新,校验版本是否和远程匹配之后,则使用临时文件夹中的manifest作为远程manifest继续更新(前提是临时文件中已经下载了project.manifest。在临时文件夹中的命名会有一个.temp后缀)此时对于下载状态为完成的不会重新下载,对于下载中的文件一般是从头开始下载。更新完成后 cocoscreator将远程的 版本文件project.manifest 作为当前本地的 project.manifest,下次更新 即用最新的 manifest文件的版本号对比接着 保存本地project.manifest文件的搜索路径,重启游戏,执行main.js。main.js中把缓存文件夹搜索路径前置到搜索路径, 进入游戏即 用到的资源 为最新的资源,达到热更新效果。

注意:下载失败了如何处理,当热更过程中出现异常,下载失败,解压失败,校验失败都会触发UPDATE_FAILED回调事件,此时所有下载失败的资源列表会记录在热更管理器中, 此时我们可以调用

assetsManager.downloadFailedAssets();

重新进入热更流程,仅下载失败的资源。

前面是理论介绍 后面是实操取证

在实操之前 先看一下工程目录结构

制作旧版本

1,首先我们需要搭建一个资源服务器,以nodejs为例

1)先创建一个nodejs目录
cd到该目录 创建一个hotUpdate目录 这个用于存放远程版本资源

2)搭建服务器之前先安装 nodejs
接着安装 Express

安装exptress指导地址

3)编辑服务器脚本
创建一个js脚本命名为server.js
将以下内容复制进去

var express = require('express');
var path = require('path');
var app = express();
app.use(express.static(path.join(__dirname, 'hotUpdate')));
app.listen(80);

最后的目录结构是:

4)测试访问服务器资源

在hotUpdate内放入一个文件 比如server.js文件

cd到 服务器脚本目录 运行命令行

node server.js 

开启服务器。
然后在浏览器输入 该服务器 内 文件的地址

http://127.0.0.1/server.js

可以查看到如下信息 说明能正常访问服务器的资源

其中127.0.0.1是访问本机的ip地址 ,如果想让任何人访问远程资源文件。可以把这个地址改成当前电脑的ip地址 .

命令行
ifconfig | grep "inet " | grep -v 127.0.0.1 查看本机ip

2,编写热更新的代码

编写hotupdate.ts文件

代码结构:

1)onload内 初始化资源管理器,同时设置本地缓存目录,设置版本对比回调和检查文件回调

onLoad() {
    this.versionStr.string = this.getCurVesion();
    this.storagePath = this.getRootPath();
    cc.log('远程版本缓存路径 : ' + this.storagePath);
    this.am = new jsb.AssetsManager('', this.storagePath, this.versionCompareHanle);
    this.am.setVerifyCallback(this.setVerifycb.bind(this));
}

setVerifycb(path,asset){
    let compressed = asset.compressed;
    let expectedMD5 = asset.md5;
    let relativePath = asset.path;
    let size = asset.size;
    cc.log("assetPath",path)
    cc.log("assetSize:",size);
    if (compressed) {
        this .label.string = "检查压缩 : " + relativePath;
        return true;
    }
    else {
        this .label.string = "检查压缩 : " + relativePath + ' (' + expectedMD5 + ')';
        return true;
    }
}

2)检查版本函数,和检查版本回调函数

3),热更函数和热更函数回调

3,编辑热更界面,并将hotupdate.ts挂在 热更界面

上图中红圈内的 文件如何来的上面已经说过 是用version_generator.js生成的,这个文件等看完教程 可以在我的公众号(亮亮同学TT)里拿到。

下面 修改version_generator.js

上图的地址是你的服务器的地址和对应版本资源的地址,version是版本号。修改成1.1.2

cd到version_generator.js同级目录 运行node version_generator.js 生成两个manifest文件如下图

将project.manifest拖到热更界面对应位置

此时版本号是1.1.2

进行构建,构建结束后需要检查一下main.js的代码
如图

有画圈的代码,在热更完后才能读取到最新的缓存资源。那么这写代码时如何生成的呢?
我们可以看到 工程目录下 有一个packages/hot-update目录 里面 main.js可以在 构建项目之后 把 这段缓存资源路径前置的代码加到main.js里面去。

编译打包。安装到手机上(电脑上更新完看不到效果的)

制作新版本
将界面上的小飞机换成小骷髅,构建项目

然后修改version_generator.js中版本号为1.1.3

运行node version_generator.js

生成 version.manifest,project.manifest

将构建后的assets,src文件,version.manifest,project.manifest 放到资源服务器中 如图

打开手机上的安装的app 当前版本是1.1.2,显示的是小飞机点击检查更新按钮 会提示有新版本 然后点击更新。更新成功版本号为1.1.3 同时 小飞机变成了小骷髅


到此 热更基础版就弄好了。

可版本回退版实际操作

在实际项目中更新版本可能不小心 携带了意外的bug 要想快速还原。那就需要回退到上个版本。实际上 cocoscreator的热更新 默认 是 如果远程版本大于本地版本 才会进行热更的,那么如何实现回退?

这个问题可以修改 版本检查函数的逻辑,即 只要版本不同就热更,这样可以通过服务器传给客户端要回退的版本就可以了 就可以更新到热和版本了

代码:

/**比较版本 版本不同则更新 返回小于0的即为需要热更*/
    versionCompareHanle( versionA : string , versionB : string ){
        console.log(`当前版本 :  ${versionA} , 远程版本 : ${versionB}`);
        let vA = versionA.split('.');
        let vB = versionB.split('.');
        for( let i = 0 ; i < vA.length && i < vB.length ; ++i ){
            let a = parseInt(vA[i]);
            let b = parseInt(vB[i]);
            if ( a === b ){
                continue;
            }
            else{
                return  -1;//这里直接返回-1 
            }
        }
        if ( vB.length > vA.length){
            return -1;
        }
        return 0;
    }

动态地址热更实际操作

那么,如果我想在远程保存不同的版本 来应对不同渠道的游戏内容和 发生意外 进行回退到其他版本呢?

针对这个问题,可以 用动态地址热更的方式解决。

因为cocoscreator认为 如果缓存地址中有版本文件 就直接用该版本文件中的版本 和 地址作为当前的 版本和 地址信息。
如果没有则用包内的project.manifest的 版本和地址信息。

所以,我们只需要动态修改缓存目录中的地址信息即可达到动态热更

packageUrl

remoteManifestUrl

remoteVersionUrl

从服务器获取最新版本的地址信息 然后判断版本是否有变化,如果有,则将 packageUrl

remoteManifestUrl

remoteVersionUrl

的地址信息替换为 最新版本的地址信息。然后在检查热更新 。
代码如下:

到目前为止cocoscreator热更新第一期基本上说完了,当中还有很多内容需要根据自己项目的需要进行修改。

关注我的公众号 亮亮同学TT 发送热更。获取完整源码及资源

75赞

mark一下

可以的,有时间试试,之前看范例的热更新还是弄不明白,这个看上去更具体一些

图片挂了。。。

我公众号有这篇文章,也有demo 。。。。。

mark,后面学习

(帖子被作者删除,如无标记将在 24 小时后自动删除)

mark~

mark一下

很详细啊,多谢多谢

:wink:

学习!!!

先收藏以后一定会用到

mark一下,死后再看

1赞

:joy:

mark一下

不错~~~~~~~~~

:wink:

mark1

图片挂了,很多东西感觉说的不够清晰,跟官方文档差不了多少,还是面向小白来写文档好点