unity热更新杂谈

热更新的含义

首先想说的是这是一个工业界提出的概念,其实没有特别严谨权威的定义。简单来说,热更新(hotfix)是指让应用能够在无需重新安装的情况下实现更新。它描述了一种方案流程,但其实在各个细分的应用领域又有一些差异,不能一概而论。

对一个游戏软件而言,为什么要更新呢?一般是出于下面几点:

  • 修复游戏bug(包括代码bug、配置bug或其他游戏资源bug)

  • 增加新的游戏内容(包括新增代码、配置或其他游戏资源)

我们可以将一个游戏软件从逻辑上拆分为程序代码部分和资源文件部分。在游戏启动时,由程序的执行文件负责执行代码逻辑、加载各种需要的资源文件,展现游戏的内容。

资源文件部分一般包括数据文件(如各种格式的配置表),图片,音视频文件,或者其它游戏程序可识别的资源文件。它的更新比较纯粹,一般直接替换或者新增文件即可。

而程序代码由于不同平台执行程序的差异性,则要变得复杂很多,并不是仅仅替换一个exe文件就完事了。

代码跨平台

所谓跨平台,可以简单理解为一份程序代码可以在多个平台上运行。它的实现方案也有很多种

  • 一次编译,到处运行(如java,实际上时依赖于不同平台都要有相对应的java虚拟机来解析“编译”出来的java字节码)

  • 一次编码,到处编译(如C/C++,需要不同平台提供语言本身的编译支持)

  • 还有lua这种嵌入式语言,依赖于不同平台实现了ANSI C,只要有C编译器的平台都可以让lua在虚拟机中运行自己的字节码

那么Unity是怎么实现跨平台的呢?

在这之前我们要再先说明几个概念:

Native code和托管代码

我们知道程序员写的程序代码最终会被转化为二进制代码后再由CPU执行。但不同架构的CPU他们的指令集一般是不同的,也就是说用来执行的程序的二进制代码也是不同的。

Native code是指以被编译为特定CPU的机器码的代码。

托管代码:编译器把代码编译城中间语言(IL),它是独立于CPU且面向对象的指令集。中间语言一般被封装在一个叫程序集(assembly)的文件中,这个文件包含了描述你所橙将的类、方法和属性的所有元数据

CLR公共语言运行时

一种虚拟机,用来做内存管理、程序集的加载、异常处理、线程同步等事情

.Net

一个抽象的平台概念(注意它是指一个概念)

.Net framework

.Net的一种实现,它包含两个主要的部分:

  • CLR的实现

  • CTS(通用类型系统)的实现

c#

仅仅是一种语言,但它是运行在.Net CLR上的一种语言

Mono

.Net 的另一种实现,也就是说它主要实现了

  • 一个c#编译器

  • CLR(mono虚拟机)

  • 一组类库

介绍完上面这些概念后,我们再来看一下Unity到底是怎么实现跨平台的

Unity引擎最底层是由C++写出的,而Mono被嵌入到了Unity当中,为Unity提供了一个完整的虚拟机运行环境。这样Mono的嵌入接口会将Mono Runtime暴露给Unity底层的C++代码。通过这些接口,开发者就可以控制Mono Runtime,以及依托于Mono Runtime的托管代码。

Unity3D的开发过程中,代码的编译主要分为两个过程:

  • 首先将对应的脚本代码编译成CIL(之后CIL还会被编译成一种位元码,生成一个CLI集合)。

  • 然后Mono在运行时将CLI集合中的位元码编译为本地运行的原生指令。

附带说一下,Mono是以dll的方式来存放程序集的,比如Assembly-CSharp.dll。这个dll(mono assembly)是一种特殊的动态链接库,扩展了Windows PE 格式,使其可含有编译后生成的IL元数据和代码。就算是再Android平台和IOS平台,它也是dll文件。我需要再解释一下为什么为什么Android的手机版apk解包出来会有dll文件。

首先Android系统是啥:

Android代码包括三部分:

  • AOSP(Android开源系统Android Open Source Project) 基于Linux内核,提供了Android系统的框架

  • GMS(Google 移动服务Google Mobile Service),由Google提供的一系列提高用户移动体验的应用和服务,包括各种服务和内购功能,还有一些 Google 的应用

  • 基于AOSP的源码开发独立的Android系统

好了,可以看到Android实际上是linux内核,那它为什么可以使用window下的dll呢?Windows下的库有两种:

一种是native code,这种只能在window下使用(因为编译器把它们编译成了windows操作系统能够识别的机器码组织形式)。严谨地来说,是链接器和加载器的不同,以及各自的系统调用压根就没有互映射性,导致了linux不能使用它们。

第二种是.Net平台编译出来的类库,这个是生成了中间语言(IL),它是由.Net来负责的,如果能够完全满足.Net的标准,那么.Net就能让它再linux上跑起来。

看到这里我们大概可以有一个稍微清晰一点的认识,我们的代码在unity编译之后被放到了某个.dll中,如果我们要做更新,那就把对应的.dll文件替换掉就行了?

诶,在android平台上确实可以这么做。而在另外一篇中提到的ILRuntime(一种商业化的热更新方案),它的基本思想也是这样。

在这种思想的指导下,开发者可以将游戏分为两个部分,Unity和Hotfix。其中主要的游戏逻辑部分也就是可能需要热更的部分都写在Hotfix当中,然后将其导出为Hotfix.dll文件供Unity使用。游戏上线后若需要更新代码,只需要修改Hotfix中的代码,然后生成新的Hotfix.dll文件热更上去即可。

然而直接通过mono来实现这种做法会被IOS平台限制(至于想了解ios是怎么限制的可以移步这篇文章)

为什么用Lua

为了绕过IOS的限制,游戏开发者想到了通过Lua这种非编译又能够跨平台的语言来开发主要的(并且是容易被修改)的业务逻辑。lua文件不需要编译,可以被打包进游戏的资源中,在游戏启动的过程中加载对应的脚本资源,进而解释执行转换为字节码,在lua的虚拟机中执行,这种天然的设计,可以规避“程序文件”的更新限制。

Unity和lua的通信方式

首先要明确一点,lua代码始终是运行在lua虚拟机中的,由于lua的运行时(虚拟机)是由纯C语言写的,所以C和lua的实际上是基于一套C语言的API(如果你想十分详尽的了解这个过程,强烈推荐去看《游戏脚本高级编程》这本书)。

在unity中,这个lua虚拟机和相关C API由lua.dll提供(或者包含了相关代码的其他集成dll)

Lua call c#

所谓lua调用c#,实际上是将c#的一些类型和方法通过C API注册到lua虚拟机中。这样lua就可以通过相关的类名、方法命来创建相关的对象和实行相关的函数方法。

为了自动化的注册想用的类型和方法,xlua设计了一套叫Wrap文件的方式。每个wrap文件都是对一个c#类的包装,在lua中通过对wrap类中函数的调用,间接的对c#实例进行操作

c# call lua

C#可以通过P/Invoke方式调用lua的dll(包含了lua运行时的实现),通过这个dll执行lua的C API,即c#是借助C/C++来与lua进行数据通信的。

在xlua的LuaDLL.cs中实现了加载lua的dll的方法

相关参考文章

Unity实现c#热更新方案探究
https://www.cnblogs.com/zblade/p/9089105.html

深入xlua实现原理
https://www.cnblogs.com/iwiniwin/p/15323970.html

wrap文件的原理与使用
https://www.cnblogs.com/msxh/p/9813147.html

Unity编译Android的原理解析和apk打包分析
https://blog.csdn.net/u011490813/article/details/54577671

Unity跨平台的机制原理
https://www.cnblogs.com/0kk470/p/7468054.html

Unity引擎编译后的程序是如何运行在iOS和Android上的?
https://www.zhihu.com/question/25045484

对C#热更新方案ILRuntime的探究
https://www.cnblogs.com/zblade/p/9041400.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 热更新探索 一、什么是Mono Mono虚拟机包含一个实时编译引擎,该引擎可用于如下处理器: x86, SPARC...
    BacteriumFox阅读 252评论 0 1
  • 引言 最近看了一下 ET 框架,本来只是研究一下网络模块,后来抽时间看一下热更框架。ET 的热更使用的不是像 to...
    忆中异阅读 3,942评论 0 4
  • 对C#热更新方案ILRuntime的探究 转载请标明出处:http://www.cnblogs.com/zblad...
    拉夫斯基丶阅读 1,528评论 0 1
  • 《腾讯桌球:客户端总结》 本次分享总结,起源于腾讯桌球项目,但是不仅仅限于项目本身。虽然基于Unity3D,很多东...
    吴秦阅读 24,303评论 12 142
  • 本文原创版权归 博客园吴秦所有,此处纯粹技术收藏,如有再转,敬请于显示位置标明原创作者及出处,以示尊重!! 作者:...
    Magic_Dong阅读 4,549评论 0 7