性感码农,在线解答:有什么问题可以扫屏幕右方二维码加我微信或者在下方留言。

之前使用quick-cocos2d-x,做过lua版本的热更新,后来转了creator,也做过creator的热更新,在这里分享一上心得。

lua版本的热更新只使用了cocos的下载功能,其它工作全都是自己实现,有兴趣的同学点击这里可以看看实现代码。这套东西是16年做的,实现了读取配置文件,比对配置文件,下载写入等等功能,对于现在来说代码里的很多API可能已经不适用了,但重在原理和功能,如果是做lua版本热更新,拿过来改改就可以跑起来。

Cocos在热更新上帮我们做了很多工作,这就导致很多同学在做热更新功能的时候只是看着文档来,但是做完了也不知道实现了什么功能,出了问题也是一头雾水。做热更新,先要了解热更新要做什么,把问题拆开来一个一个去解决。这篇文章里不去讲细节实现,而是告诉你Cocos热更新的原理。理解透了这套原理,做热更就是小菜一碟。

如何去真正理解透彻,建议读完这篇文章,找一款root过的安卓手机,安装RootExplore,配合Android Studio,调试,打印功能,再加上官方的Demo,把不明白的地方挨个都扣清楚。

热更新的核心功能

  • 读取配置文件
  • 从远程下载新的配置文件并和本地进行对比
  • 下载更新文件,并写入本地
  • 设置搜索路径的优先级

理解了这几个功能,如果可以自己徒手实现,热更新的可定制性将大大提升。如果实现不了,就使用Cocos自带的,基本也能满足我们的需求。

配置文件

记录当前游戏版本的文件,Creator使用的是mainfest文件,看一下里面的内容就可以知道,是当前的所有游戏资源文件的MD5值,在这里,你可以把脚本文件也当成游戏资源文件的一种。这个文件游戏本地放一个,远程服务器放一个,进游戏时下载远程文件和本地进行对比,筛选出MD5值不一样的文件,然后进行下载。下载完成后,把新的mainfest文件写入本地。下次再进入游戏时,读取新的mainfest文件和远程对比。配置文件也可以是其它格式的文件,json,lua,js等等。它就仅仅是记录版本的信息而已,只要你能在游戏中读取到这个文件的内容,什么格式都ok。配置文件的生成可以直接使用官方的脚本文件,也可以自己用python写,目的都是生成配置信息而已。

从远程下载新的配置文件并和本地进行对比

下载功能creator已经帮我们做了,读取配置文件也帮我们做了,我们要做的仅仅是拿着两个文件的数据进行比对,告诉creator要不要更新,更新什么,下载文件之后放到哪个目录。

下载更新文件,并写入本地

逐个下载上一步中比对出来的要下载的文件,并放入到预先设置好的目录。

设置搜索路径优先级

搜索路径优先级是说当去加载一个资源的时候,会先去优先级高的路径寻找,如果没有,再逐级向下寻找。Creator中的搜索路径是以Array存储的。比如一张头像图的路径是UI/HeadImg/1.png,搜索路径的优先级是['/Path_a/', '/Path_b/'],那么会先去Path_a文件夹下寻找有没有UI/HeadImg/1.png,如果没有,再去Path_b寻找。

以下是官方文档中在main.js文件中添加的代码,也就是搜索路径的优先级设置。单看这里的设置,根本看不出来什么,HotUpdateSearchPaths这个数据是什么?是从哪里存储进去的?

if (cc.sys.isNative) {
    var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');
    if (hotUpdateSearchPaths) {
        jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));
    }
}

我们去看官方的Demo工程中的HotUpdate.js文件中的一些代码:

this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');

this._storagePath在脚本中多次用到,这个变量就是我们自己设置的文件下载目录的路径,blackjack-remote-asset可以更改成任何你喜欢的目录名称,最好是数字+字母或者纯字母。jsb.fileUtils.getWritablePath()获取到的是可写目录,这个目录的路径是什么?安卓使用root过的手机下载RootExplore查看/data/data/游戏包名/files/blackjack-remote-asset,这就是我们存放下载的资源的目录,也是我们设置的搜索路径优先级最高的目录。更新完成之后,新版本的mainfest文件同样也会被放入这里。

为什么要放入这里?我们打出apk包安装到手机之后,是无法更改apk里的内容的,getWirtablePath获取到一个可写目录,这是原生Android给开发者开放的接口。你可以在这里存放一些需要修改的文件,IOS同理。

再看下面一段代码

if (needRestart) {
    this._am.setEventCallback(null);
    this._updateListener = null;
    // Prepend the manifest's search path
    var searchPaths = jsb.fileUtils.getSearchPaths();
    var newPaths = this._am.getLocalManifest().getSearchPaths();
    console.log(JSON.stringify(newPaths));
    Array.prototype.unshift.apply(searchPaths, newPaths);
    // This value will be retrieved and appended to the default search path during game startup,
    // please refer to samples/js-tests/main.js for detailed usage.
    // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
    cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
    jsb.fileUtils.setSearchPaths(searchPaths);

    cc.audioEngine.stopAll();
    cc.game.restart();
}

从以上代码中可以看到,是在更新完毕,准备重启的时候存入HotUpdateSearchPaths。下载完所有资源,并把下载的新资源的存放目录的路径获取到,使用Array.prototype.unshift.apply(searchPaths, newPaths)生成新的搜索目录数组,并把可写目录放到前面,存入本地。游戏再次启动的时候,在main.js文件中获取到当前的搜索目录,设置进去,使热更新生效。

原理就是这样。

回顾热更新的核心功能

  • 读取配置文件
  • 从远程下载新的配置文件并和本地进行对比
  • 下载更新文件,并写入本地
  • 设置搜索路径的优先级

Creator的AssetsManager替我们做了几项工作,读取配置文件,下载更新文件并写入本地。

在照着官方文档做过程中可能会遇到各种问题,但是都可以通过细读代码解决,还可能会由于Creator版本问题导致Demo运行不起来,没有什么好办法,去改代码,哪里报错看哪里,哪里出错改哪里。代码对我们程序员来说是难题吗?不是,难的是解决问题的思路和方法。

有什么问题可以在下方留言。

性感码农,在线解答。

发表评论

电子邮件地址不会被公开。 必填项已用*标注