Unity 是使用很广泛的游戏引擎,值得深入研究。现在业界的很多项目都与此有关,比如虚拟人物、虚拟现实场景等,对 Unity 技术的深入研究,值得探讨。
其中的游戏热更新是重要的应用技术,但是Unity官方对这一技术的支持有限,并且受限于应用市场的政策,需要特别关注。
在这个页面里,能找到与 Unity 相关的热更新笔记。
游戏热更新
游戏热更新:游戏或者软件更新时,无需重新下载客户端进行安装,而是在应用程序启动的情况下,在内部进行的资源或者代码更新。用户重启客户端就能实现客户端更新的需求或者功能;或者也可以这样说:不需要通过在应用商店更新应用,就可以实现新的需求和功能。
为什么要用热更新?
热更新的优点:
- 迅速修复Bug – 避免重新下载安装包,游戏内部及时更新Bug;能够缩短用户取得新版客户端的流程,改善用户体验。
- 减小安装包的体积 – 非核心资源上传服务器,运行时动态加载剩余资源
- 迅速更换游戏”内核” – 狸猫换太子,绕过审核,迅速对游戏进行更新
就拿iOS来说,如果你需要更新应用,需要经过一系列的苹果提审流程,少则几天,多则一个月,审核周期比较难控制。试想下,如果你的上线游戏出现了一个严重的bug,此时如果没有热更新,那么只有两种选择:第一种:提交更新包到应用商店,等审查(时间不受自己控制);第二种:坐视不管。无论哪种方式,你都应该清楚,可以提前准备简历和打包行李了。
还有一个原因,对于大型游戏来说,玩家更新成本太大。App Store上,你更新一个应用,其实是重新下载一次,而不是增量的更新。
如果有了热更新机制会怎么样呢?你可以通过热更新推送给每一个用户,在较短的时间(自己控制)内解决这个bug。
热更新基本流程:
- 版本号的比较,如果版本号不同才继续以下流程(version.txt记录版本号,可选)
- 下载资源服务器上的对比文件(files.txt记录所有文件md5码,类似于目录)
- 确定下载列表,将最新下载的对比文件和本地旧对比文件对比,记录缺少或不同的文件。(利用files.txt中的md5码实现此步骤)
- 根据下载列表,下载所需的资源。(一般放在Application.persistentDataPath)
- 解压(如果文件压缩过需要先解压,可选)
- 保证下载成功后,用最新的对比文件覆盖本地的对比文件(更新目录)
Unity 热更新
Unity热更新是指能够在不重新安装app包的情况下,来完成更新新的功能和解决开发中遇到的bug。
Unity热更新主要是包含资源更新与代码更新两大板块:
- 资源更新: 目前Unity 的Assetsbundle与Addreessable机制都能很好的做到资源更新。做资源更新时还要根据版本,比对前后版本的资源变化来做增量的资源更新。
- 代码更新: 目前做热更新的解决方案有 Lua, C#, JavaScript/TypeScript等方案。
热更新一般可以分为美术资源热更新和代码热更新。美术资源热更新的方案一般就是采用AssetBundle方式。代码热更新方案一般可以分为以下两种方法:
第一种方案:
(1)项目开发中,可以将部分逻辑提取至一个单独的代码库工程中,打包为DLL;
(2)将DLL打包为AssetBundle;
(3)Unity程序动态加载AssetBundle中的DLL文件,使用Reflection机制来调用代码。
这个方案看起来很完美,能支持C#级别的代码热更新,但是它有限制:苹果官方禁止Ios下的程序热更新;JIT在Ios下无效。所以这个方案在Android下还是可以用用的。但是一般情况下,一个项目不可能为Android和Ios开发两套不同的热更新方案,所以这个方案实际上也就无法应用到项目之中了。
hybridclr试验
我使用 hybridclr 在 Windows 上进行了一下小试验,可以对 Windows 的 Unity 游戏进行热更新,步骤很简单,简单记录一下:
- 下载HybridCLR 体验项目,并对对应的Unity版本打开。
- 根据安装HybridCLR在Unity里把HybridCLR package安装上。
- 通过Unity工程里的菜单HybridCLR ==> Build ==> Win64,构建 Win64 的 Unity 游戏。
- 如果游戏能正常运行,则把第1点里提到的体验项目的目录:hybridclr_trial\Release-Win64 拷贝出来,可以再单独运行一下HybridCLRTrial.exe看是否正常。
- 用Visual Studio 2019打开体验项目的 C# 代码,修改 Assets/HotUpdateMain.cs 文件,添加几行测试代码,比如:
.Log("=======添加测试代码,测试热更新是否成功=======");
Debug
.Log("=======再测试一下=======");
Debug
.Log("=======再测试一下2222======="); Debug
- 通过Unity工程里的菜单HybridCLR ==> Build ==>BuildAssetsAndCopyToStreamingAssets,重新构建 Win64 的 Unity 游戏。
- 拷贝 hybridclr_trial\HybridCLRData\HotUpdateDlls\StandaloneWindows64 目录下由第6步生成的文件,全部拷贝到第4步里的HybridCLRTrial.exe目录,替代掉相同文件,此时 HybridCLRTrial.exe 还在运行,内容没有改变,但是替代相同文件并不会提示占用问题。
- 关闭HybridCLRTrial.exe,再重新运行程序,即能看到新更新的日志能正常显示出来。
Android hybridlr 实验
在 Android 下操作 hybridlr,流程基本上和 Windows 上一样,不过默认情况下,AssetBundles 是针对 Windows 来编译的,在为 Android 生成 apk 包的时候,需要重新针对 Android 来编译 AssetBundles,即在菜单 HybridCLR ==> Buil ==> BuildAssetsAndCopyToStreamingAssets 针对 Android 目标平台生成 AssetBundles,如果不这样做,会提示类似正面的错误:build target error.
步骤基本上和[[20220720180750#hybridclr试验]]里一样,不过,第7步的路径需要修改为:hybridclr_trial/Assets/StreamingAssets,把里面的文件全部拷贝(即热更新)到 Android 手机指定的目录。
原demo中,默认是从asset目录读取,不方便我们修改,将其替换成cache目录,在代码 LoadDll.cs 里,把正面这行代码改为 cache 目录:
private string GetWebRequestPath(string asset)
{
//var path = $"{Application.streamingAssetsPath}/{asset}";
var path = $"{Application.temporaryCachePath}/{asset}";
if (!path.Contains("://"))
{
= "file://" + path;
path }
if (path.EndsWith(".dll"))
{
+= ".bytes";
path }
return path;
}
这样,你 build and run 这个 Unity Demo 的时候,就会看到下面的界面:
这个是一个错误界面,是因为没有正确加载应的 dll 库。修正方法很简单,把代码目录下的 hybridclr_trial/Assets/StreamingAssets 所有的内容,一股脑拷贝到手机目录
内部存储/Android/data/com.Dev.HybridCLRTrial/cache
目录下,拷贝完后大致是这样一个情形:
现在杀掉手机进程,重新跑起来这个app,就能看到正常显示的界面,如下图所示:
现在到了在 Android 上测试热更新的时候了,把 HotUpdateMain.cs 修改为如下测试代码,并且在 Unity 编辑器里再次编译(通过菜单 HybridCLR ==> Buil ==> BuildAssetsAndCopyToStreamingAssets):
void Start()
{
.Log("这个热更新脚本挂载在prefab上,打包成ab。通过从ab中实例化prefab成功还原");
Debug.LogFormat("hello, {0}.", text);
Debug
.AddComponent<CreateByCode>();
gameObject
.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码=======");
Debug
.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码,手动更新=======");
Debug
//Debug.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码,手动更新22222=======");
.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码,手动更新333333333=======");
Debug
.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码,手动更新444444444=======");
Debug
.Log("=======看到此条日志代表你成功运行了示例项目的热更新代码,手动更新555555555=======");
Debug}
再次杀掉进程重启,则显示如下运行界面,表明成功热更新:
参考资料
https://bbs.huaweicloud.com/blogs/370395,这个资料有点老了,但是算是简单快速入门的资料,可以一读,操作上略有不同。
https://github.com/focus-creative-games/hybridclr_trial,把这个 readme 先读懂,基本上就地 HybridCLR 有了基本的认识。
Android 这一节重点参考资料:Unity-huatuo热更新调研