如果項目很大,代碼量很多滴劲,不僅會使包體變大攻晒,編譯時間變長,還會導致各種編譯報錯班挖。比如:
ARM64 branch out of range (154869072 max is +/-128MB)
Unity提供了一種被稱作托管代碼剝離( managed code stripping )的方案用來刪除未使用或無法訪問的代碼鲁捏。托管代碼剝離從托管程序集中刪除代碼,包括從項目中的 C# 腳本構建的程序集萧芙、作為包和插件一部分的程序集给梅,以及 .NET Framework 中的程序集假丧。
Unity 使用稱為 Unity 鏈接器(Unity linker)的工具對項目程序集中的代碼執(zhí)行靜態(tài)分析。靜態(tài)分析識別在執(zhí)行期間無法訪問的任何類动羽、類的部分包帚、函數(shù)或函數(shù)的部分。此分析僅包括構建時存在的代碼运吓,因為在 Unity 執(zhí)行靜態(tài)分析時不存在運行時生成的代碼渴邦。可以使用 **托管剝離級別 **來控制剝離的程度拘哨。
配置托管代碼剝離:
- 轉到編輯 > 項目設置 > 播放器几莽。
- 在其他設置中,找到優(yōu)化一欄宅静。
- 將 Managed Stripping Level 屬性設置為所需的值章蚣。
屬性 | 功能 |
---|---|
Disabled | 不會移除任何代碼。如果使用 mono ,這是默認設置 |
Minimal | 只在 UnityEngine 和 .net 類庫中搜索未使用的代碼姨夹。不會刪除任何用戶編寫的代碼纤垂。此設置最不可能導致任何意外的運行時行為如果使用 IL2CPP ,這是默認設置磷账。 |
Low | Unity會搜索一些用戶編寫的程序集,以及所有 UnityEngine和 .net 類庫來尋找未使用的代碼峭沦。此設置應用一組規(guī)則,這些規(guī)則刪除一些未使用的代碼逃糟,但將意外后果的可能性降到最低吼鱼,例如使用反射的運行時代碼的行為更改。 |
Medium | Unity 部分搜索所有程序集以查找無法訪問的代碼绰咽。此設置應用一組規(guī)則菇肃,這些規(guī)則剝離更多類型的代碼模式以減少構建大小。盡管 Unity 不會刪除所有可能無法訪問的代碼取募,但此設置確實會增加發(fā)生不良或意外行為更改的風險琐谤。 |
High | Unity會對所有程序集進行廣泛搜索,以找到無法訪問的代碼玩敏。在這個設置中斗忌,Unity優(yōu)先考慮的是減少大小,而不是代碼穩(wěn)定性旺聚,并刪除盡可能多的代碼织阳。這種搜索可能比較低的剝離級別花費更長的時間。徹底測試你的應用砰粹,仔細使用[Preserve]屬性和link.xml文件唧躲,以確保Unity鏈接器不會剝離關鍵代碼。 |
使用 托管代碼剝離 需謹慎,防止必要的代碼被剝離惊窖。我們可以使用 Preserve 或 Link.xml 來保護代碼。
Preserve:
可以使用 Preserve 來防止 Unity 鏈接器剝離代碼的特定部分厘贼。如果您的應用程序生成 Unity 執(zhí)行靜態(tài)分析時不存在的運行時代碼界酒,這將很有幫助;例如嘴秸,通過反射毁欣。Preserve 要么為 Unity 鏈接器提供關于它不應該剝離哪些代碼模式的一般指導,要么提供不剝離特定的岳掐、已定義的代碼部分的指令凭疮。
例如:
class Foo
{
[Preserve]
public void PreservedMethod(){}
}
Link.xml :
也可以在項目中包括一個名為 link.xml 的 .xml 文件,以保留特定程序集或程序集的一部分的列表串述。xml 文件必須存在于 Assets 文件夾或項目中的 Assets 文件夾的子目錄中执解,并且文件中必須包含 <linker> 標記。Unity 鏈接器將保存在 link.xml 文件中的任何程序集纲酗、類型或成員視為根類型衰腌。
例如:
<linker>
<!--Preserve types and members in an assembly-->
<assembly fullname="AssemblyName">
<!--Preserve an entire type-->
<type fullname="AssemblyName.MethodName" preserve="all"/>
<!--No "preserve" attribute and no members specified means preserve all members-->
<type fullname="AssemblyName.MethodName"/>
<!--Preserve all fields on a type-->
<type fullname="AssemblyName.MethodName" preserve="fields"/>
<!--Preserve all fields on a type-->
<type fullname="AssemblyName.MethodName" preserve="methods"/>
<!--Preserve the type only-->
<type fullname="AssemblyName.MethodName" preserve="nothing"/>
<!--Preserving only specific members of a type-->
<type fullname="AssemblyName.MethodName">
<!--Fields-->
<field signature="System.Int32 FieldName" />
<!--Preserve a field by name rather than signature-->
<field name="FieldName" />
<!--Methods-->
<method signature="System.Void MethodName()" />
<!--Preserve a method with parameters-->
<method signature="System.Void MethodName(System.Int32,System.String)" />
<!--Preserve a method by name rather than signature-->
<method name="MethodName" />
<!--Properties-->
<!--Preserve a property, it's backing field (if present),
getter, and setter methods-->
<property signature="System.Int32 PropertyName" />
<property signature="System.Int32 PropertyName" accessors="all" />
<!--Preserve a property, it's backing field (if present), and getter method-->
<property signature="System.Int32 PropertyName" accessors="get" />
<!--Preserve a property, it's backing field (if present), and setter method-->
<property signature="System.Int32 PropertyName" accessors="set" />
<!--Preserve a property by name rather than signature-->
<property name="PropertyName" />
<!--Events-->
<!--Preserve an event, it's backing field (if present), add, and remove methods-->
<event signature="System.EventHandler EventName" />
<!--Preserve an event by name rather than signature-->
<event name="EventName" />
</type>
</assembly>
</linker>
詳細請參考 Unity 官方文檔:
https://docs.unity.cn/cn/current/Manual/ManagedCodeStripping.html
如果你做了托管代碼剝離,但是在IOS還是會報ARM64 branch out of range觅赊,那么 你可以打開Xcode工程進行如下設置:
把主工程和UnityFramework工程的優(yōu)化等級都設為 -Os
環(huán)境:
Unity:2021.3.2
Xcode:13.3.1