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 托管代码剥离的主要内容,如果未能解决你的问题,请参考以下文章

Unity 托管代码剥离

如何解决 Unity3D iOS 版本上的 AOT 和代码剥离

csharp 从Unity生成的.sln文件中剥离设置

使用 P/Invoke 从 Unity 高效地与非托管代码对话

怎么给Unity写一个原生的插件

unity3d优化-代码篇(不定期更新)