Unity 托管代码剥离
Posted 天涯过客TYGK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ,这是默认设置。
Managed Stripping Level 等级设置
Low Unity会搜索一些用户编写的程序集,以及所有 UnityEngine和 .net 类库来寻找未使用的代码。此设置应用一组规则,这些规则删除一些未使用的代码,但将意外后果的可能性降到最低,例如使用反射的运行时代码的行为更改。
Medium Unity 部分搜索所有程序集以查找无法访问的代码。此设置应用一组规则,这些规则剥离更多类型的代码模式以减少构建大小。尽管 Unity 不会删除所有可能无法访问的代码,但此设置确实会增加发生不良或意外行为更改的风险。
High Unity会对所有程序集进行广泛搜索,以找到无法访问的代码。在这个设置中,Unity优先考虑的是减少大小,而不是代码稳定性,并删除尽可能多的代码。这种搜索可能比较低的剥离级别花费更长的时间。彻底测试你的应用,仔细使用[Preserve]属性和link.xml文件,以确保Unity链接器不会剥离关键代码。
使用 托管代码剥离 需谨慎,防止必要的代码被剥离。我们可以使用 Preserve 或 Link.xml 来保护代码。
Preserve:
可以使用 Preserve 来防止 Unity 链接器剥离代码的特定部分。如果您的应用程序生成 Unity 执行静态分析时不存在的运行时代码,这将很有帮助;例如,通过反射。Preserve 要么为 Unity 链接器提供关于它不应该剥离哪些代码模式的一般指导,要么提供不剥离特定的、已定义的代码部分的指令。
例如:
class Foo
[Preserve]
public void PreservedMethod()
Link.xml :
也可以在项目中包括一个名为 link.xml 的 .xml 文件,以保留特定程序集或程序集的一部分的列表。xml 文件必须存在于 Assets 文件夹或项目中的 Assets 文件夹的子目录中,并且文件中必须包含 标记。Unity 链接器将保存在 link.xml 文件中的任何程序集、类型或成员视为根类型。
例如:
<!--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>
详细请参考 Unity 官方文档:
https://docs.unity.cn/cn/current/Manual/ManagedCodeStripping.html
如果你做了托管代码剥离,但是在ios还是会报ARM64 branch out of range,那么 你可以打开Xcode工程进行如下设置:
优化等级设为 -Os
把主工程和UnityFramework工程的优化等级都设为 -Os
转自:https://www.jianshu.com/p/23ee1a176a90
以上是关于Unity 托管代码剥离的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 Unity3D iOS 版本上的 AOT 和代码剥离