zoukankan      html  css  js  c++  java
  • Cocos2dx-lua中资源热更新

      项目选择C++ 和 lua 混合, 看中的就是lua代码的热更新优势,想想之前客户端出现了bug,需要玩家重新下载安装包,这带来的流失率是挺高的; 而随着现在app体积日益增大,动辄几十兆、上百兆的安装包重复下载,对用户体验是非常不友好的;另外appstore的审核也是严格、标准可变的,很容易审核被拒,导致应用的问题无法及时修复。而选择lua做为开发语言,就能做到几乎无感知的修复、增加应用的新功能,对于开发者可以及时修复问题,而对于玩家来说则能获得更好的游戏体验。从某狐刚推出某耀客户端项目,客户端购买、咨询量激增来看,这个功能还是很有吸引力的。

      热更新方案,一开始的设计是单文件更新,思路是:

      1、打包的时候利用脚本对全部的资源文件:包含lua脚本、游戏的图片、音频资源生成一份版本文件

      2、客户端启动的时候从服务器下载版本文件,跟本地的版本文件进行对比,生成更新列表,然后进行更新

      上述方案的优势在于:

      1、资源服务器只需要存一套资源文件、

      2、不用考虑客户端版本与服务器版本之间差异过大,导致数据不对等的问题

      3、方案实现简单,使用的成本也低,可以实现一些取巧操作(资源服务器直接改某个文件的差异值,让客户端直接更新等)

      但是在实际的使用过程中也发现了该方案存在不足:如果待更新的资源过多,那么就会产生大量的http请求,严重的影响了下载体验,而且单个文件的更新失败,需要一个非常复杂的断点续传的方案来控制整体更新。

      在这里提一下一般客户端实现的文件下载功能:利用curl库,发起请求进行文件下载。这就会引发两个问题:请求量及请求响应。上述方案的核心点是根据版本文件生成差异列表,然后再单独下载差异列表中的每个文件,所以每下载一个文件,就会发起一次请求,如果某次更新有上千个文件,那么单个客户端更新所发起的请求量将是巨大的。上千次请求,引发上千次的响应等待,对带宽及玩家的等待时间都将产生巨大的影响!

      因此我们需要新的更新方案:更新是对差异文件进行更新,之前将差异对比放在了客户端处理阶段,那么可以将差异对比放在更新包生成的阶段,将版本间的差异文件提取出来,合并成一个压缩包,客户端直接下载这一个压缩包再解压,实现功能的更新。我们将这个方案称为差异包更新

      实现这个方案,需要考虑到:

      1、客户端每次只下载一个文件,需要严格保证下载到正确的资源

      2、客户端更新存在版本延时的问题,需要有跨版本的差异包

    1、严格保证资源的正确下载

      (1)网络不稳定的处理:

      手机客户端考虑到移动网络的不稳定,容易导致断网、超时的问题。前面提到的单文件更新方案,在更新的过程中单个文件下载失败,需要一套非常复杂的断点续传方案,才能控制好整体的功能更新,我们是非常粗鲁的直接重新下载。。。调整到下载压缩包之后,就可以很方便的利用curl库提供的功能,来实现断点续传功能:

    curl_easy_setopt(_curl, CURLOPT_RESUME_FROM, localLen)

      核心就是上述代码,CURLOPT_RESUME_FROM, 表示从参数3的位置来写入本地文件,而参数3的值也很容易获取,直接使用引擎的getDataFromFile方法getSize就能拿到当前阶段本地文件的大小。

      (2)差异包更新失败的处理:

      之前的单文件更新方案,假如存在错误,可能也只是单个文件或单独几个文件出现问题,修复比较方便。但是在差异包更新方案中,每次的更新是单个压缩包的更新,就会存在:

      a.压缩包下载失败导致客户端出现重大功能异常

      b.版本与版本之间生成了错误的差异列表导致更新异常

      c.客户端资源版本不统一,如何下载到统一的更新包

      我们的应对方案是:保留单文件更新功能,在压缩包下载失败时进行单文件更新;采用更可靠的生成文件差异值的方案,由一台设备统一生成更新包,针对不同版本生成不同的差异包。

    2、更可靠的差异生成方案:

      在上面有提到,差异列表生成错误、客户端版本有差异两个问题,在这里具体谈一下采用一套更可靠的差异生成方案:

      (1)差异值的生成:

      在单文件更新方案里,我们是简单的对文件大小进行MD5处理,得到一个差异值,然后更新对比中对md5值进行对比,生成差异列表。这个方案就有很大的概率出现md5值一致,但是实际却需要更新的情况,因此我们改用获取文件的修改时间,这样就大大降低了上述情况出现的概率了。

      (2)差异包的生成:

      差异值的获取,差异包的生成, 在这里讲一下思路。这里举个例子说明客户端版本差异:客户端A的当前版本为1, 客户端B的当前版本号为2,此时发布版本3的更新,这个时候客户端A和客户端B的更新列表是存在差异的,该如何处理?在单文件更新方案下,这不存在问题,A和B都是以3的版本文件,在客户端本地直接生成差异列表,去下载对应的文件即可。但是在差异包更新方案中,就需要生成如1-3,2-3这样的版本差异包。而且游戏客户端的更新是比较频繁的,就表示每次更新,所需要的差异包是非常多的,因此考虑到不必要的工作复杂度提升,需要提出一个基准包的概念。每次进行了底包(玩家重新安装了客户端)更新,底包对应的资源版本就是一个基准的,无论玩家多久不更新,他都有一个基准的包,因此生成差异包的时候,可以针对这个基准包生成一份差异包,这样就能保证功能的正常更新了。因此我们的差异包就包含了:版本间的差异包,与基准版本的基准差异包。

      我们控制一个版本跨度,比如5,设定一个基准版本0,假如客户端A的版本号是6,资源服务器的版本号是7,版本跨度是1,在我们设定的跨度之间,客户端A更新的时候就下载6-7之间的差异包;客户端B的版本号是5,与资源服务器的版本跨度是2,下载5-7的包;客户端C的版本号是1,与资源服务器的版本跨度是6,大于我们设定的限值了,这个时候就下载0-7的基准差异包。 这样就能保证不同版本的客户端,也能下载到统一的更新资源。

      解决了上述问题,我们实现的差异包更新方案,在实际的体验中,就是一个字:快!在带宽一致的情况下,大概算了一下,之前需要10s才能完成的更新,现在只要1s不到的时间就能下载好,再根据设备配置的差异存在一定的解压时间,但是总时间是小于之前那个方案的。这个方案不涉及到引擎相关(最多就是用引擎的接口拿获取文件大小),因此可以加入到使用到了热更新方案的不同开发项目中去。

  • 相关阅读:
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
  • 原文地址:https://www.cnblogs.com/zhong-dev/p/9535501.html
Copyright © 2011-2022 走看看