徹底解決IL2CPP 開啓Strip Engine Code選項後帶來的崩潰問題

IL2CPP根據C#生成的Cpp代碼行數巨大,達到百萬行級別,進而引起iOS平臺可執行文件超過60MB的問題。因此在適當的時候有必要對UnityEngine下的代碼進行Strip。但是這樣做容易帶來如下的問題:
ReportException: UnityLogError Could not produce class with ID XXX.
This could be caused by a class being stripped from the build even though it is needed.
Try disabling 'Strip Engine Code' in Player Settings.
其中XXX代表被Strip掉但是資源所需要的YAML ClassID.

之所以會出現這樣的問題,目前的猜測是Unity進行Code Strip時,只分析一下幾個方面所用到的類:

  • C#代碼:Assembly-CSharp.dll、firstpass.dll、各插件Dll.
  • Resources資源:BuildSettings裏面的場景引用的資源和Resources文件夾下面的資源
  • link.xml:Assets文件夾下面開發者可創建一個link.xml作爲Code Strip白名單。另外觀察Jenkins打包日誌可以發現Unity安裝目錄下playbackEngines文件夾內含Unity自己的一套link.xml白名單

這樣來看上述Crash發生的原因就比較明確了,那些打入AssetBundle的文件使用了Unity的其他類,但是同時在以上三個分析範圍之外,Unity會將其Strip掉;當從AssetBundle進行加載時,由於缺少對應的類造成Deserialize失敗,進而引起崩潰。

瞭解以上原因後,解決方案就呼之欲出了。只需要得到資源所用到的所有Unity引擎類,將其加入至link.xml即可。

  • UnityEngine.Dll: 一般的做法是獲取所有Prefab、場景文件中的組件進行彙總,這裏說一個更簡單的辦法,直接觀察Unity YAML的結構,很容易就能發現以下格式指明瞭Unity引擎類的ID:
    --- !u!XXX
    其中XXX代表YAML ClassID,去Unity Manual上查表即可得到對應的類名。
  • UnityEngine.UI.Dll:沒有YAML ClassID可查,只能加載出Prefab時Get一下Component來判斷,可能遺漏的情況是ScriptableObject中對其進行了引用。
  • UnityEditor.Dll:一個很特殊的情況,如果AssetBundle裏使用到了AniamtorController,那麼就需要UnityEditor下面的AnimatorController相關的幾個類(還有AnimationState、Transition之類),直接添加進link.xml顯然沒什麼意義。解決方案也很簡單,在Resources下面增加一個空的AnimatorController,讓Unity自己處理。

值得注意的是,這一塊Unity自己的Bug也不少,出現奇怪的問題不妨先去issueTracker和Fix List看看 :)

PS: IL2CPP相關的實現其實就在Unity的安裝目錄下,包含完整的從分析到生成C++、編譯的邏輯,有興趣可以逆向Dll看一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章