空包 cocos的热更新是基于对比列表和远程文件列表的
2023-09-08
1132浏览
空包 cocos的热更新是基于对比列表和远程文件列表的的热更新是基于对比本来文件列表和远程文件列表的md5实现的,如果有多个远程资源库,就可以拿来作为分包方案。首先是,策划要根据一定的策略,将动态加载的资源分成几个包。这里要注意的是版本号,因为热更新首先对比的是版本号,因此要确保后一个分包的版本号要高,哪怕是后面热更新之后,也还要高于热更新之后的版本号,建议版本号这样设置:游戏大版本.

cocos的热更新是基于原始文件列表和远程文件列表的md5对比。 如果有多个远程资源库,可以作为包投递解决方案。 大概的流程是这样的:

1.确定外包策略

首先,规划应将动态加载的资源按照一定的策略划分为若干个包。 比如游戏等级,80级之前一包,120级之前一包,200级之前一包; 或级别。 这个逻辑需要通过规划来确定。 前期不会用到的资源放在中期包中,中期不会用到的资源放在后期资源包中。

如果你想去GooglePlay,限制是100M空包,可以将第一个包做成一个没有任何动态加载资源的空包,上传到GooglePlay,播放器下载并开始更新第一个包的资源。 相比obb承包的用处,统一采用热更新的方式,不需要研究obb相关技术,但iOS也可以使用这种策略。缺点:首先需要提供自己的远程资源服务器,如果您有大量用户,则需要 CDN; 其次,登录游戏需要下载大量资源,玩家可能会流失; 第三,热更新需要上传到服务器的资源很多,因为多个资源包分别对应一个服务器资源空包,每个资源都需要上传到服务器

第二代外包资源

契约分配策略确定后,让规划者填写一份不同包资源对应的配置表,然后需要编写脚本根据计划配置表形成下一生不同的资源包。 如:p0-空包、p1-第一个资源包、p2-第二个资源包,以此类推。 下面的脚本根据配置表sub_pack_and_config生成不同的包。

def gen_update_assets(update_path, black_list):
    """
    将工程目录的 res 和 src 拷贝到 update_path
    """
    print "[make version] => copy asset to update directory", update_path
    print "black list len", len(black_list)
    project_path = version.get_project_path()
    assert_path = os.path.join(update_path, "assets")
    if not os.path.exists(assert_path):
        os.makedirs(assert_path)
    src_path = os.path.join(assert_path, "src")
    if os.path.exists(src_path):
        shutil.rmtree(src_path)
    res_path = os.path.join(assert_path, "res")
    if os.path.exists(res_path):
        shutil.rmtree(res_path)
    opfile.copy_dir(os.path.join(project_path, "src"), src_path, black_list)
    opfile.copy_dir(os.path.join(project_path, "res"), res_path, black_list)
def get_black(pack_list):
    black = {}
    for i, sub_name in enumerate(pack_list):
        cfg = sub_pack_and_config[sub_name]
        black_dir_list = cfg["resList"]
        black[sub_name] = meta.get_uuid_list_from_path(black_dir_list)
    return black
def replace_native(update_path):
    plat = version.get_platform()
    project_path = version.get_project_path()
    # android 母包用 p0 的资源, ios 母包用 p1 资源
    sub_name = "p0" if plat == "android" else "p1"
    update_path_pack = os.path.join(update_path, sub_name, "assets")
    src_path = os.path.join(project_path, "src")
    if os.path.exists(src_path):
        shutil.rmtree(src_path)
    src_path_p = os.path.join(update_path_pack, "src")
    shutil.copytree(src_path_p, src_path)
    res_path = os.path.join(project_path, "res")
    if os.path.exists(res_path):
        shutil.rmtree(res_path)
    res_path_p = os.path.join(update_path_pack, "res")
    shutil.copytree(res_path_p, res_path)
def build():
    pack_list = sub_pack_and_config.keys()
    pack_list.sort()
    black = get_black(pack_list)
    update_path = version.get_update_path()
    url_root = version.get_update_path()
    for i, sub_name in enumerate(pack_list):
        black_list = black.get(sub_name)
        is_update = i > 0
        pack_path = os.path.join(update_path, sub_name)
        update_url = url_root + (sub_name if is_update else "p1") + "/"
        ver = version.get_version(i)
        print "\nversion", ver
        print "update_url", update_url
        gen_update_assets(pack_path, black_list)
        manifest.gen_manifest(ver, update_url, pack_path)
    print "\n"
    is_update = version.get_is_update()
    if not is_update:
        pack_path = os.path.join(update_path, "p0")
        replace_native(update_path)
        manifest.replace_manifest(pack_path)
        mainjs.change_main_js()

三生成对比文件列表

签约资源可用后,根据资源的来世生成文件列表清单。 这个过程和热更新生成manifest的过程是一样的,只是比较的文件目录变成了上一步生成的通用包资源。 这里需要注意的是版本号。 由于热更新首先会比较版本号,所以需要保证下一个包的版本号较高。 即使侧面热更新后,也应该低于热更新后的版本号。 建议版本号这样设置:游戏的主要版本。 父包的版本。

第一次更新后,只需更新包版本号即可:

如果重新打开父包:

这样就保证了后续的版本号必须低于之前的版本号,保证资源可以热更新。

下面的脚本根据资源生成一个清单。 官方的是js,这里是python。 我们使用python来实现手动打包过程。

def gen_manifest(ver, update_url, update_path):
    """
    生成热更新的资源
    update_url 服务器资源 url
    update_path 本地资源存放路径
    :return:
    """
    print "[make version] => make hot update assets",
    manifest = {
        'packageUrl': update_url + "assets/",
        'remoteManifestUrl': update_url + 'project.manifest',
        'remoteVersionUrl': update_url + 'version.manifest',
        'version': ver,
        'assets': {},
        'searchPaths': [],
    }
    print "packageUrl", manifest["packageUrl"]
    print "remoteManifestUrl", manifest["remoteManifestUrl"]
    print "remoteVersionUrl", manifest["remoteVersionUrl"]
    update_path = os.path.normpath(update_path)
    assert_path = os.path.join(update_path, "assets")
    for root, dirs, files in os.walk(assert_path):
        assets = manifest["assets"]
        for filename in files:
            path = os.path.join(root, filename)
            rel_path = path[len(assert_path) + 1:].replace('\\', '/')
            assets[rel_path] = {'size': opfile.get_file_size(path), 'md5': opfile.get_file_md5(path)}
    # 热更新远程文件,需要上传到资源服务器上
    remote_manifest_path = os.path.join(update_path, 'project.manifest')
    opfile.write_json_file(remote_manifest_path, manifest)
    # 去掉 assets 和 searchPaths,即为 version 文件内容
    manifest.pop("assets")
    manifest.pop("searchPaths")
    remote_version_path = os.path.join(update_path, 'version.manifest')
    opfile.write_json_file(remote_version_path, manifest)
    print "local update asset path", assert_path
    print "local update manifest", remote_manifest_path
    print "local update version", remote_version_path
def replace_manifest(update_path):
    """
    :param update_path: 新 manifest 所在路径
    :return:
    """
    root = version.get_client_root()
    client_manifest = root + "assets/project.manifest"
    project_path = root + "build/jsb-default"
    assert_path = os.path.join(update_path, "assets")
    remote_manifest_path = os.path.join(update_path, 'project.manifest')
    print "[manifest] => use manifest", remote_manifest_path
    # 替换 client 中的 manifest
    # shutil.copy(remote_manifest_path, client_manifest)
    # print "[manifest] => replace manifest", client_manifest
    # 替换原生工程中的 manifest
    uuid = meta.get_uuid_form_meta(client_manifest)
    dirname = uuid[0:2]
    project_manifest_path = os.path.join(project_path, "res", "raw-assets", dirname, uuid + ".manifest")
    shutil.copy(remote_manifest_path, project_manifest_path)
    print "[manifest] => replace manifest", project_manifest_path
    # 替换热更新资源中的 manifest
    update_manifest_path = os.path.join(assert_path, "res", "raw-assets", dirname, uuid + ".manifest")
    shutil.copy(remote_manifest_path, update_manifest_path)
    print "[manifest] => replace manifest", update_manifest_path

四次触发下一个数据包

当玩家达到一定条件时,触发风暴,更改玩家本地的manifest文件,然后进行热更新流程下载资源。 需要注意的是,玩家的本地清单有两个路径。 如果没有更新过,则是打包后asset目录下的project.manifest; 如果已更新,则将远程manifest文件下载到热更新目录中。 向下。 因此,在更改本地manifest文件时,需要进行一些判断。 下面提供了一封辞职信,这是我们之前项目中使用的。

LocalCmd.sub = function(args, localManifestPath) {
    DebugLog("cmd: test, arg:", args);
    let update_url = StrUtils.format("{0}{1}/p{2}/", HttpUtils.URL_ROOT, MsicUtils.getNameOS(), args);
    let ret = HttpUtils.changeManifest(update_url, localManifestPath);
    if (ret) {
        cc.game.restart();
    }
    return "ok";
};
/**
 * 修改热更新地址,用于更新分包下载
 * */
HttpUtils.changeManifest = function(update_url, localManifestPath) {
    if(!window.jsb){
        return;
    }
    DebugLog("update url", update_url);
    DebugLog("hot update path", Const.hotUpdatePath);
    DebugLog("local manifest path", localManifestPath);
    try {
        let manifestPath = localManifestPath;
        let downloadManifest = Const.hotUpdatePath + "project.manifest";
        if (jsb.fileUtils.isFileExist(downloadManifest)) {
            DebugLog("remote manifest");
            manifestPath = downloadManifest
        } else {
            DebugLog("local manifest", localManifestPath);
            if (!localManifestPath) {
                return;
            }
            // 没有热更过要新建一下热更新目录
            if (!jsb.fileUtils.isDirectoryExist(Const.hotUpdatePath)) {
                jsb.fileUtils.createDirectory(Const.hotUpdatePath);
            }
        }
        DebugLog("last manifest path", manifestPath);
        let loadManifest = jsb.fileUtils.getStringFromFile(manifestPath);
        let manifestObject = JSON.parse(loadManifest);
        manifestObject.packageUrl = update_url + "assets/";
        manifestObject.remoteManifestUrl = update_url + "project.manifest";
        manifestObject.remoteVersionUrl = update_url + "version.manifest";
        let afterString = JSON.stringify(manifestObject);
        let isWritten = jsb.fileUtils.writeStringToFile(afterString, Const.hotUpdatePath + '/project.manifest');
        DebugLog("Written Status : ", isWritten);
        return isWritten;
    } catch (error) {
        DebugLog("change manifest error", error.message || error);
        return false;
    }
};

五项热点更新

更改热更新文件并重新启动游戏后,就会进入正常的热更新流程。 热更新完成后,再次重启即可进入游戏。

整个计划是这样的。 考虑到每次下载都会有损失,尤其是GooglePlay下载空包后,第一次需要下载好几G的资源,这是不可接受的。 最后我们使用obb来发送包,这样也节省了下载和发送包的带宽。 成本。

以上内容均来自网络搜集,如有侵权联系客服删除

图文阅读
最新文章
淘宝自补发快递:安全但成本高,真实礼品快递空包代发可解决?
2022-10-30 08:02:14
甩货:通过低价促销搞定基础销量和评价的有效方法
2022-10-30 08:02:14
掌握这些关键点,轻松做好拼多多店铺运营
2022-10-30 08:02:14
利用直通车等多种方式,快速提升淘宝商品销量
2022-10-30 08:02:14
空包裹刷单利益链曝光:快递员、公司、商家均参与,用户信息成牺牲品
2022-10-30 08:02:14
快手小店补单方法大揭秘!如何利用短视频平台流量提升店铺销量?
2022-10-30 08:02:14
9 年电商人陈升分享:淘宝蓝海无货源年利润超 200W 的秘诀
2022-10-30 08:02:14
空包 cocos的热更新是基于对比列表和远程文件列表的
2022-10-30 08:02:14
 
QQ在线咨询
客服热线
客服微信号
STU006