代碼熱更新
有支持ios的熱更方案都有個共同點:更新后代碼都是解析執行。如果按其更新前是否解析執行,可以分為兩大類:
一類是某些模塊甚至整個游戲都采用解析執行。這是最傳統的方式,目前市面上所有主流方案(xLua,slua,tolua,ILRuntime,jsb等等)都支持這種方式。
這種方式:
1. 或多或少都會有些侵入性;
2. 基於性能、實現便利性等的考慮,一般在游戲中要以原生的方式跑,這些原生跑的代碼出了bug時,在這種方式下是無能為力的;
3. 如果使用的腳本是動態類型語言,還會帶來代碼維護困難的問題;
4. 可以新增功能,有的游戲甚至可以做到一次下載,后續不用整包更新。
另外一類是原生方式,如果有bug,把邏輯重定向到新的,解析執行的邏輯。
這種方式:
1. 侵入性低,后期項目也可以使用;
2. 正常邏輯是原生方式運行,有問題只是局部切換到解析執行,所以性能比較好;
3. 會導致代碼段增大,增大正比於注入的類的數量;
4. 這種方式往往難以新增功能。
第二種方式是接下來討論的重點,方便起見,我們稱之為“熱修復”,熱修復最早的成熟方案是xLua提供,經過兩年來的使用已經逐漸被接受,tolua#后來也加入了這功能,也有一些網友基於ILRuntime做了熱修復功能。
InjectFix
https://mp.weixin.qq.com/s/-J7zxnh-_H6kRH3G_LyMxw
InjectFix就是一個熱修復的實現。那它和其它熱修復方案又有什么不同呢?
設想這么個場景,我們有一個一千行代碼的函數,其中有一行有問題,我們需要修復它。如果用xLua,需要用lua去重新實現一遍這個函數,工作量大。而基於ILRuntime的熱修復,由於其補丁是另一個程序集,它無法直接訪問原類的私有成員,所以那999行正常代碼一般也不能直接使用,需要做較多修改。而InjectFix不需要用lua,也不需要像ILRuntime熱修復那樣另外建一個工程把那一千行邏輯重實現。只需要在Unity原工程直接改掉這行代碼,然后標注這函數要更新即可。
InjectFix還有其它優勢:
1. 運行時非常小巧,僅100K左右,比各lua方案,ILRuntime都要小很多,而且不依賴第三方庫,純C#實現;
2. 支持每個游戲生成一份自己私有的補丁格式,私有的指令定義。這樣相比通用的lua原代碼,lua字節碼,clr程序集都更安全些。
3. 支持Assembly-CSharp.dll之外的dll的修復。
4. 免代碼生成,更干凈。
它也有缺點,不支持新增類,也不支持在已有類新增字段,修bug還是夠用的,但難以通過熱更為游戲增加新功能。InjectFix就一個純粹的修bug工具而已。
各熱更方案群提問頻率最高的問題之一:這方案會不會導致我游戲蘋果審核不通過。讓我們看看蘋果的熱更新條款:

可以看到最新條款允許下載代碼解析執行,但前提是不能通過新增特性和功能來把程序改得(和審核時相比)面目全非。再看看通常被拒時的理由中的Guideline 2.5.2里的一句:Your app, extension, or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval。有“新增特性和功能”能力的熱更新方案的尷尬之處在於有“改得面目全非”的能力。而InjectFix從它提供的能力(只能修改已有函數)來看,並不具備“新增特性和功能”的能力,這本來是弱點,放在這里卻成為合規性的保證了。
鏈接:https://www.zhihu.com/question/345639690/answer/825301379
InjectFix的作者,同時也是xLua的作者來答一波。
先回題主的問題:其實這問題在騰訊開源公眾號發布的公告那也描述得挺清楚的,簡而言之,InjectFix是xLua的hotfix功能(公告那稱之為“熱修復”)的升級版。
和ILRuntime的區別從用戶視角看,ILRuntime要更新的整個模塊要挪到一個dll里頭,“整個模塊”解析執行。而InjectFix不需要對工程重構,當工程不需要更新時,全部代碼都以原生方式運行,有更新的話,僅僅待更新那少數幾個函數切換到解析執行。
而CSHotfix,XIL,也是“熱修復”方案,據我所知,它們訪問原類的私有變量之類是要特殊的寫法,一個類成員方法往往避免不了這些寫法,因此你要修復一個很大的函數,對原來邏輯的重新實現往往是無可避免的。而InjectFix在原工程哪行錯誤改哪里即可。
ET好像是個使用了ILRuntime的一個C#框架吧。和InjectFix關系不大,屬於兩類東西沒可比性。
如果僅僅修C# bug,目前方案中,InjectFix應該是最好用的。缺點嘛,公告也說了,不能新增功能。其實這“不能”,更多是人為的設定,InjectFix在對Unity協程,閉包的支持中其實是包含了對新增class的支持,只不過人為約束了僅這些場合使用。公告也分析了,這樣更符合蘋果的熱更新條款。
至於某層提到的產品化問題,這里也答一下:
InjectFix(內部叫iFix,因外部商標被注冊被迫改名,打聽的時候記得說iFix)項目在xLua對外開源不久后就有想法了做了,在2017年下半部開始研發,2018年初對內發布。目前“已知”有9個項目在用,其中4個已經正式上線,沒上線的也用於他們平時體驗版本的修復,第一個使用iFix的項目至今已經使用了1年多。9個說多也不多,但新項目用ue的居多,所以說少其實也不少。
至於“多年脫產”嘛,也是,但前面也說了,InjectFix和xLua同一個作者,xLua在2015年研發,作者在熱更新方面領域也默默耕耘了4年多了,期間和很多內部項目交流相關需求,在外部xLua的兩個千人+的群,前期也有很多交流。iFix從設計之初就考慮了很多項目的痛點。脫產也有脫產的好處,不會優先考慮自家的問題,在一個公共組件中做了很多私有特性,脫產不可怕,脫產+閉塞才可怕。然而個人還是蠻喜歡和項目交流的,開源也是為了和更多的人交流。
