介紹一種基于Mono的Unity熱更新方案

《介紹一種基于Mono的Unity熱更新方案》

熱更新是Unity3D開發(fā)總也繞不過去的話題矢渊,甚至影響到了開發(fā)語言战转,程序架構(gòu)、人員配置予弧,不可謂不重要刮吧。文章開頭先從一些大家都熟知的東西帶入。熱更新目前有很多成熟的方案掖蛤,筆者很早前因為工作需要了解了一些信息杀捻,大體分幾個流派

  • Lua流派/CSharp轉(zhuǎn)Lua流派
  • CSharp流派
  • JS/TS流派

各個流派均有成熟的框架,優(yōu)劣勢在此不再展開蚓庭,選擇時往往是結(jié)合自己團隊的情況來取舍致讥。從方向上看仅仆,筆者更看好Lua流派,Lua天生就作為腳本語言設(shè)計垢袱,集成到游戲引擎中作為邏輯腳本似乎是一件很合理的事情蝇恶。筆者對Lua不是很熟悉,也曾因此在工作面試中被鄙視惶桐,從個人喜好上撮弧,還是喜歡CSharp這門語言多一點,當然這個喜好也是建立在特定環(huán)境下的姚糊,語言層面的優(yōu)劣在此也不再展開贿衍。在聊新的方案前,先從頭聊一些熱更新方面的知識做引子救恨。

熱更新的重災區(qū)是在iOS系統(tǒng)贸辈,因為一些眾所周知的原因,Unity最初的Mono運行時在iOS平臺下只能以full AOT模式運行肠槽,這樣就無法實現(xiàn)熱更新了梁呈。這里也引出了運行模式的概念,大家熟知的有:

  • JIT運行

    Mono髓抑,V8等引擎默認運行模式胜榔,這種模式是可以動態(tài)Load代碼的,也就是可以更新代碼邏輯寂纪。但是在iOS系統(tǒng)上是被禁止的席吴。

  • AOT運行

    提前編譯成本機代碼,運行效率可以比肩原生代碼捞蛋,Unity的Mono引擎在iOS系統(tǒng)上即以此模式運行孝冒,但是不能更新代碼。

  • Interpreter運行

    即解釋器執(zhí)行拟杉,顧名思義庄涡,腳本語言以此方式運行,并沒有生成本地機器碼搬设,目前各個熱更流派均是以此方式實現(xiàn)熱更新穴店,代價是效率低一些。

Lua天生是以解釋器運行的焕梅,具有體積小迹鹅,集成靈活等特性作為大家的首選腳本,也發(fā)展出了jit模式來解決其他平臺上的性能問題贞言,有xLua斜棚,toLua等成熟框架。

CSharp也發(fā)展出了ILRuntime框架來支持解釋模式,從而實現(xiàn)了CSharp熱更新弟蚀。

那么JS/TS呢蚤霞,筆者以前以為V8引擎一直有解釋器的,不然iOS上的Chrome是怎么運行的呢义钉?帶著這個問題查了下才發(fā)現(xiàn)V8確實加了解釋器昧绣,并不是很久以前。所以現(xiàn)在JS/TS流派也發(fā)展出了成熟的框架比如Puerts捶闸。

那么Mono呢夜畴?再繼續(xù)查了下,也有删壮。Mono的解釋器命運就比較曲折了贪绘,從Mono第一個版本便有,再到后來光榮退場央碟,然后重新出山税灌,當然是肩負了使命的。既然再加回來當然還要再進一步亿虽,AOT和Interpreter都可以在iOS上運行菱涤,如果可以讓熱點代碼跑在AOT,容易變更的代碼跑在Interpreter洛勉,兩部分代碼不需要關(guān)心自己的運行時不是更好嗎粘秆?再繼續(xù)查了下,也有坯认,Mono內(nèi)部已經(jīng)實現(xiàn)了兩套運行模式的交互部分翻擒,在aot編譯時提前生成了交互代碼氓涣,運行時的代碼可以無感知的相互調(diào)用牛哺,并且完善度已經(jīng)相當高。

  • Mixed-Mode Execution

    Mono支持的一種運行模式劳吠,混合了AOT和Interpreter引润,在執(zhí)行沒有AOT的程序集時,自動將程序集切換到Interpreter內(nèi)執(zhí)行痒玩,所以支持動態(tài)Load代碼淳附。

事情在朝著好的方向發(fā)展,似乎一切都比較合理蠢古。從mono的提交日志看奴曙,2018年開始充斥著大量的[interp]模塊提交,幾乎占到了總提交量的1/3草讶,mono的這個模塊發(fā)展很快洽糟。反觀Unity官方mono,恰好停留在[interp]模塊加入前,便不再合并mono主干坤溃。具體原因我們不再此猜測拍霜,只是這樣就需要我們自己動手了。

既然運行時已經(jīng)支持薪介,剩下的工作就是集成到UnityEngine內(nèi)與Il2cpp親密無間祠饺。在此之前我們先以Unity的默認執(zhí)行框架做引子,以下為筆者個人理解汁政,不正確的地方請以官方為準道偷。

Unity Il2cpp執(zhí)行框架

1號通道最初是通過Mono的Internal call來實現(xiàn)的,Il2cpp同樣使用此方式來實現(xiàn)(C)到(A)的請求记劈。

2號通道是UnityEngine通過Il2cpp 然后invoke上層接口來實現(xiàn)回調(diào)试疙。

0號通道我們先稱之為magic,實現(xiàn)一些定制特性抠蚣,我們先忽略祝旷。

如果要在Unity項目中實現(xiàn)Mono 的Mixed-Mode Execution,我們需要在此系統(tǒng)內(nèi)再加入一個Mono runtime嘶窄,同時綁定上述三條通道怀跛,這里先說下我們的第一種綁定方案(icall綁定):

  • 針對1號通道,Mono原生即支持Internal call(我們簡稱icall)柄冲,那么在Mono中直接執(zhí)行unity assembly吻谋,然后將icall調(diào)用直接指向(A)即是最直接的方式。
  • 針對2號通道需要在(B)層做些手腳现横,通過查代碼我們發(fā)現(xiàn)Il2cpp的Method實際是一個函數(shù)指針漓拾,那么查找到需要回調(diào)的函數(shù),并使指針指向我們的實現(xiàn)戒祠,然后再Invoke Mono內(nèi)的相同函數(shù)即實現(xiàn)了hook功能骇两,即實現(xiàn)了UnityEngine的回調(diào)。

通過以上兩種方式我們在自己的Mono runtime內(nèi)綁定了大部分的Unity功能姜盈。為什么是大部分呢低千,這里可以實現(xiàn)icall綁定的前提是所有icall綁定傳遞的對象只有一份內(nèi)存,并且是在(A)內(nèi)馏颂,UnityEngine.Object即是此目的示血。Unity當然不會就此收手,magic就無用武之地了救拉,除此還有其他一些特性难审,最麻煩的是0號magic通道,比如MonoBehaviour亿絮、Coroutine告喊、傳遞給(A)一個.Net 的Stream等等拂铡。這里因為Unity做了一些特殊處理,具體實現(xiàn)我們不得而知葱绒,即使勉強實現(xiàn)了也無法保證以后兼容性感帅,所以我們使用了Wrapper的方式。這里有兩種實現(xiàn)方式地淀,后面再詳細介紹失球。

我們再來看看加上Mono runtime后的結(jié)構(gòu):

加入Mono runtime

如上面所說,我們需要綁定(H)內(nèi)的icall指向(A)即新增了通道5-3帮毁,同時需要hook(B)內(nèi)的函數(shù)指針實現(xiàn)回調(diào)实苞,即新增了通道4-5。

同時為了處理magic情況烈疚,我們提供兩種方案黔牵,一種是手動在(F)內(nèi)實現(xiàn)綁定接口(Unity的icall綁定大部分也是這種無規(guī)則的手動實現(xiàn),所以給我們的自動綁定帶來了很多麻煩)這種方案上層用戶(I/K)完全無感知爷肝,只是因為這部分是由c/cpp實現(xiàn)猾浦,對部分團隊并不友好。所以我們新增了通道6灯抛,也就是我們的第二種綁定方案(Adapter綁定):

Adapter是指在(D)中指定一些需要在(I/K)內(nèi)使用的程序集金赦,在構(gòu)建時為這些程序生成兩個Adapter程序集,分別位于(E)和(J)对嚼,這樣當用戶(I/K)調(diào)用(D)內(nèi)的程序接口時會自動通過通道6調(diào)用夹抗,調(diào)用方無感知,同時通道6是雙向的纵竖,即同時支持調(diào)用與回調(diào)漠烧。

另外指出的是(H)是直接使用的UnityEngine.*.dll,只需重新綁定icall即可靡砌,(F)/(E)/(J)內(nèi)的綁定代碼均由代碼生成器生成已脓,即除非需要手動實現(xiàn)icall綁定,通道3/4/5/6均自動生成乏奥。

兩種方案是否給框架增加了復雜性呢摆舟,其實在開發(fā)過程中,為了保持簡潔筆者在這兩種方案中反復切換了多次邓了,每個單獨方案都能實現(xiàn)絕大部分的功能,但是總會讓一小部分特定的問題復雜化媳瞪。比如我們?nèi)渴褂肁dapter綁定可以完成需求嗎骗炉?其實是可以的,但是碰到Unity使用runtime來支持的特性蛇受,單純的從CSharp層來實現(xiàn)復雜度會大大增加句葵,或者需要用戶修改程序,而且后續(xù)功能的兼容和擴展性會低很多。兩種方式一起用乍丈,雖然給綁定生成器帶來了復雜性剂碴,用戶使用反而簡單一些,所以保留了兩種綁定方案轻专。

至于用戶的程序集是在(K)內(nèi)執(zhí)行還是在(I)內(nèi)執(zhí)行忆矛,用戶可以自己根據(jù)實際需求來配置,綁定生成器會在構(gòu)建時自動觸發(fā)请垛,根據(jù)配置生成不同的工程催训,然后將此工程以pod庫的形式提供給主項目集成。主項目需要在podfile中引用后執(zhí)行

pod install

即可鏈接成最終執(zhí)行項目宗收,以上即是筆者本次介紹的方案漫拭,詳細使用細節(jié)請移步這里。此方案支持iOS平臺下Assembly.Load接口混稽。Android平臺建議直接使用Unity的Mono運行時采驻,同樣支持Assembly.Load接口,這樣在架構(gòu)上不需改動匈勋。


此方案其實構(gòu)思已久挑宠,期間做了不少可行性測試,一直因抽不出時間拖著未實現(xiàn)颓影,最終也因2020年這個年終閑的時間長了些才得空實現(xiàn)了出來各淀,其間縫合多個程序邊界并實現(xiàn)自動化的復雜度還是超出了預期,總算最終走通了诡挂,因為感覺到自己可以調(diào)配的精力非常有限碎浇,也深知獨立開發(fā)很難使這個框架完善,所以決定開源出來璃俗,也順便取了個名字:PureScript奴璃,起碼保持從用戶角度看來是一個簡潔、單純的腳本框架城豁。

如果大家有興趣苟穆,后面再補充詳細實現(xiàn)細節(jié),目前項目已經(jīng)開源唱星。對此方案有興趣的同學歡迎提交PR或者Star雳旅。

添加一個錄屏

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市间聊,隨后出現(xiàn)的幾起案子攒盈,更是在濱河造成了極大的恐慌,老刑警劉巖哎榴,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件型豁,死亡現(xiàn)場離奇詭異僵蛛,居然都是意外死亡,警方通過查閱死者的電腦和手機迎变,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門充尉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衣形,你說我怎么就攤上這事驼侠。” “怎么了泵喘?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵泪电,是天一觀的道長。 經(jīng)常有香客問我纪铺,道長相速,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任鲜锚,我火速辦了婚禮突诬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芜繁。我一直安慰自己旺隙,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布骏令。 她就那樣靜靜地躺著蔬捷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪榔袋。 梳的紋絲不亂的頭發(fā)上周拐,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音凰兑,去河邊找鬼妥粟。 笑死,一個胖子當著我的面吹牛吏够,可吹牛的內(nèi)容都是我干的勾给。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锅知,長吁一口氣:“原來是場噩夢啊……” “哼播急!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喉镰,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤旅择,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后侣姆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體生真,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年捺宗,在試婚紗的時候發(fā)現(xiàn)自己被綠了柱蟀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚜厉,死狀恐怖长已,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情昼牛,我是刑警寧澤术瓮,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站贰健,受9級特大地震影響胞四,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伶椿,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一辜伟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脊另,春花似錦导狡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踩麦,卻和暖如春枚赡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背靖榕。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工标锄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茁计。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓料皇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親星压。 傳聞我的和親對象是個殘疾皇子践剂,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容