ChuanXin 发表于 2022-5-24 16:28

Unity 托管代码剥离

如果项目很大,代码量很多,不仅会使包体变大,编译时间变长,还会导致各种编译报错。比如:
ARM64 branch out of range (154869072 max is +/-128MB)
Unity提供了一种被称作托管代码剥离( managed code stripping )的方案用来删除未使用或无法访问的代码。托管代码剥离从托管程序集中删除代码,包括从项目中的 C# 脚本构建的程序集、作为包和插件一部分的程序集,以及 .NET Framework 中的程序集。

Unity 使用称为 Unity 链接器(Unity linker)的工具对项目程序集中的代码执行静态分析。静态分析识别在执行期间无法访问的任何类、类的部分、函数或函数的部分。此分析仅包括构建时存在的代码,因为在 Unity 执行静态分析时不存在运行时生成的代码。可以使用 **托管剥离级别 **来控制剥离的程度。
配置托管代码剥离:


配置托管代码剥离

转到编辑 > 项目设置 > 播放器。在其他设置中,找到优化一栏。将 Managed Stripping Level 属性设置为所需的值。
属性功能Disabled不会移除任何代码。如果使用 mono ,这是默认设置Minimal只在 UnityEngine 和 .net 类库中搜索未使用的代码。不会删除任何用户编写的代码。此设置最不可能导致任何意外的运行时行为如果使用 IL2CPP ,这是默认设置。LowUnity会搜索一些用户编写的程序集,以及所有 UnityEngine和 .net 类库来寻找未使用的代码。此设置应用一组规则,这些规则删除一些未使用的代码,但将意外后果的可能性降到最低,例如使用反射的运行时代码的行为更改。MediumUnity 部分搜索所有程序集以查找无法访问的代码。此设置应用一组规则,这些规则剥离更多类型的代码模式以减少构建大小。尽管 Unity 不会删除所有可能无法访问的代码,但此设置确实会增加发生不良或意外行为更改的风险。HighUnity会对所有程序集进行广泛搜索,以找到无法访问的代码。在这个设置中,Unity优先考虑的是减少大小,而不是代码稳定性,并删除尽可能多的代码。这种搜索可能比较低的剥离级别花费更长的时间。彻底测试你的应用,仔细使用属性和link.xml文件,以确保Unity链接器不会剥离关键代码。
使用 托管代码剥离 需谨慎,防止必要的代码被剥离。我们可以使用 Preserve 或 Link.xml 来保护代码。

Preserve:
可以使用 Preserve 来防止 Unity 链接器剥离代码的特定部分。如果您的应用程序生成 Unity 执行静态分析时不存在的运行时代码,这将很有帮助;例如,通过反射。Preserve 要么为 Unity 链接器提供关于它不应该剥离哪些代码模式的一般指导,要么提供不剥离特定的、已定义的代码部分的指令。

例如:
class Foo{        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工程进行如下设置:


优化等级设为 -Os

把主工程和UnityFramework工程的优化等级都设为 -Os
<hr>
环境:
Unity:2021.3.2
Xcode:13.3.1
页: [1]
查看完整版本: Unity 托管代码剥离