Cocos Creator AssetBundle 游戏分包及热更新方案落地

本文详细介绍了Cocos Creator中实现游戏模块更新的方案,包括热更新和模块更新的定义,资源的划分,特别是针对灵活Bundle和远程Bundle的下载优化思路,通过改造UrlTransform管线实现路径替换,减少不必要的网络下载。
摘要由CSDN通过智能技术生成

  有一个很常见的需求,在上一篇也提到过。
  我们希望所有频繁变动业务都划分为一个个AssetBundle,在游戏过程中需要的时候下载这部分内容,同时如果有要更新的时候,能够在不重启游戏的前提下热更新模块。(基础需求)
  一部分AssetBundle在包含在apk内,这些Bundle是用户游戏运行后立即且必要的资源,但同时希望保持在游戏中热更的基础特性。(优化)
  本文主要给出解决该需求的具体实现方案。

1. 定义

1.1 热更新和模块更新

  对于不在Asset Bundle中的资源更新,以下称为热更新,热更新由原生代码触发执行,不受js脚本影响,热更新完成后启动游戏引擎,这部分更新资源包括main.js、assets目录中本地和内置Bundle、jsb-adapter目录、src目录。
  对于划分在Asset Bundle下的资源更新,以下称为模块更新

1.2 不同的Bundle

  根据需求,我们将一些Bundle包含在apk内,并在有更新版本时更新,这类Bundle以下称为灵活Bundle;只存在apk中,且只跟随热更新时更新的,以下称为本地Bundle只存在远程服务器上,在需要时下载或更新的,以下称为远程Bundle

1.3 资源划分

  资源(包括脚本)划分为两个大部分——不频繁变动频繁变动部分。
  不频繁变动的部分为底层架构和常用稳定方法,如对网络接口的封装、时间戳格式化、资源管理器等等,这部分内容和业务基本无关
  频繁变动的部分为业务相关部分,根据业务内容分割成AssetBundle,其中包括大厅、子游戏、活动等。
 

2. 模块更新

2.1 更新清单结构

{
   
	bundleName1 : {
   
		version : 勾选md5打包生成,用于比对Bundle是否有修改,传入loadBundle参数
		ver : 版本号,如果version不同,切远程ver大于本地才更新
		url : 远程更新路径(apk中的初始清单上,灵活Bundle填写Bundle Name)
		resVer : 热更新版本,非必要,根据具体方案自行决定
	},
	bundleName2 : {
   
		...
	},
	...
}

  以上结构根据项目实际情况指定。

2.2 下载优化思路

  对于灵活Bundle,一开始本地加载,当发现远程有更新版本时,加载远程路径,这时候会在缓存目录中发现,下载了Bundle中的所有文件,即使和本地包内的资源相同,但是因为路径发生变化,Cocos的资源管理器依然认为,我们需要的是不同的文件。
  对于远程Bundle,第一次远程加载,当发现有新的版本时,如果路径和之前的不一致,也会将新的资源完全下载下来。我们可以将不同版本的资源放在一个路径下,但是那样会难以管理。所以还是将不同版本的Bundle资源放在不同路径下,方便删除等操作。
  我们需要修改Cocos的UrlTransform管线行为。这里简单通俗介绍一下管线和任务,以及我们为什么修改UrlTransform管线。

2.2.1 Cocos管线和任务是什么?

  管线是一些方法组合成的数组,任务是这些方法之间传递的一个对象。当我们执行一个任务时,比如加载Bundle,管线开始之前,将我们的参数包装成一个对象,之后传递给第一个方法获取Bundle的真实地址,并把地址存在这个对象身上,再传递给第二个方法去查看本地是否存在缓存,直到运行完数组中的最后一个方法得到最终结果或中途某一方法出错得到一个错误,返回给我们。(以上只是举例,不代表实际存储类型和过程)

2.2.2 Cocos内置的三条管线

  transformPiple(转换资源路径管线):获取配置信息 -> 生成请求资源对象 -> 反序列化uuid -> 添加md5 -> 获取子包信息(subpackage)。
  loadPiple(加载资源管线):分析参数 -> 转换路径 -> 下载资源 -> 解析资源。
  fetchPiple(预加载管线):分析参数 -> 转换路径 -> 下载资源。

2.2.3 TransformPiple

  从上可以看出,不管加载方式如何,都一定会走transformPiple,我们在这个管线之后追加方法,如果资源已经存在本地,则将返回路径改为本地,这样,后面的下载过程则会优先在本地寻找,不会实际网络下载。

2.2.4 缓存路径从何而来?

  我们确定了在transformPiple修改目标路径的方案,那么我们如何指定新的路径呢?
  首先,灵活Bundle存在apk中的assets目录下,我们可以在游戏启动时,先调用一次loadBundle加载灵活Bundle,在bundle._config上包含了这个Bundle中所有的资源信息。代码如下:

let cache = {
   };	//灵活bundle本地缓存
let bundleConfig = {
   }; //灵活bundle路径配置
cc.assetManager.loadBundle(bundleName,(err,bundle:cc.AssetManager.Bundle)=>{
   
	if(err != nil){
   
		return;
	}
	bundleConfig[bundle.name] = {
   
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CocosCreator游戏热更新是指在不重新发布游戏的情况下,通过网络下载新的资源或代码,实现游戏内容的更新。具体实现方式可以通过以下步骤来完成: 1. 在CocosCreator中使用资源管理器将需要热更新的资源打包成zip文件,并上传到服务器上。 2. 在游戏启动时,通过网络请求获取服务器上的版本信息和需要更新的资源列表。 3. 将需要更新的资源下载到本地,并进行解压和替换。 4. 重启游戏,使新的资源生效。 下面是一个简单的示例代码: ```javascript // 获取服务器版本信息和需要更新的资源列表 let xhr = cc.loader.getXMLHttpRequest(); xhr.open("GET", "http://yourserver/version.json", true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) { let response = xhr.responseText; let versionInfo = JSON.parse(response); let remoteVersion = versionInfo.version; let remoteAssets = versionInfo.assets; checkUpdate(remoteVersion, remoteAssets); } }; xhr.send(); // 检查是否需要更新 function checkUpdate(remoteVersion, remoteAssets) { let localVersion = cc.sys.localStorage.getItem("version"); if (localVersion !== remoteVersion) { // 需要更新 cc.sys.localStorage.setItem("version", remoteVersion); updateAssets(remoteAssets); } else { // 不需要更新 startGame(); } } // 更新资源 function updateAssets(remoteAssets) { let storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "/") + "remote-assets"; let am = new jsb.AssetsManager("", storagePath, (version, asset) => { // 下载进度回调 }); am.updateRemoteManifest(remoteAssets); am.checkUpdate(); } // 启动游戏 function startGame() { // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值