Unity中的StrippingLevel

StrippingLevel的作用

StrippingLevel是用来减少打包出来的player的体积

如图。第一个是选择Strip Byte Code的包的大小,第一个是选择的Disabled的打出来的包的大小,明显的Strip Byte Code的包体积小于没有进行剥离的包,大概1M。
这里写图片描述

StrippingLevel选项的副作用

使用Stripping Level需要注意的是,有可能会导致一些API执行过程中报异常,比如选择Strip Byte Code下,HttpWebRequest就会报异常:System.NotSupportedException,原因是被Strip出去了。
这里写图片描述

  /// <summary>
    /// 获取下载文件的大小
    /// </summary>
    /// <returns>The length.</returns>
    /// <param name="url">URL.</param>
    public static long GetLength (string url) {
        HttpWebRequest requet = HttpWebRequest.Create(url) as HttpWebRequest;
        requet.Method = "HEAD";
        HttpWebResponse response = requet.GetResponse() as HttpWebResponse;
        UnityEngine.Debug.LogFormat("GetLength StatusCode:{0}", response.StatusCode);
        return response.ContentLength;
    }

利用link.xml手动排除不能被剥离的的类

<linker>
      <assembly fullname="mscorlib">
                  <type fullname="System.Reflection" preserve="all"/>
                  <type fullname="System.Security.Cryptography" preserve="all"/>
                  <type fullname="System.Runtime.CompilerServices" preserve="all"/>
                  <type fullname="System.Runtime.InteropServices" preserve="all"/>
                  <type fullname="System.Diagnostics" preserve="all"/>
                  <type fullname="System.Security" preserve="all"/>
                  <type fullname="System.Security.Permissions" preserve="all"/>
      </assembly>
</linker>

参考链接:https://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html

<think>我们正在处理关于Unity AotStubs脚本的问题。首先,需要明确AotStubs的作用以及如何配置它们。根据Unity的AOT(Ahead-of-Time)编译机制,在某些平台(如iOS)上,由于禁止JIT(Just-In-Time)编译,Unity会使用AOT编译。然而,AOT编译有时无法处理一些动态代码,因此需要AotStubs(存根)来提前为这些动态代码生成编译代码。 引用[2]提到Unity使用C#脚本,而引用[3]展示了一个按钮脚本的例子。这些脚本在运行时可能需要动态生成代码,但AOT平台不支持运行时生成代码,因此需要AotStubs。 作用: AotStubs脚本主要用于在AOT编译时提前为那些可能在运行时动态生成的代码提供存根(Stub),从而避免运行时错误。例如,使用反射、泛型虚方法或者动态生成委托等情况,在AOT平台可能无法正常工作,因为AOT编译器无法预知这些动态代码的存在。通过AotStubs,我们可以提前告诉编译器需要为哪些类型和方法生成代码。 配置方法: 1. **创建AotStubs脚本**:通常,我们需要创建一个C#脚本,其中包含一些空的或者标记性的方法,这些方法代表了可能在运行时动态使用的代码。例如,如果我们有一个泛型方法,我们可以在AotStubs中为特定的类型参数调用它,这样AOT编译器就会为这些类型生成代码。 2. **将脚本放在预编译目录**:为了让AOT编译器在编译时能够处理这些存根,通常需要将AotStubs脚本放在一个预编译的目录下(如Assets目录下的某个文件夹),确保它们在其他脚本之前被编译。 3. **使用`Preserve`属性**:为了防止AOT编译器剥离这些存根方法,可以使用`[UnityEngine.Scripting.Preserve]`属性标记这些类或方法。 4. **触发编译**:在存根脚本中,我们不需要实际调用这些方法,只需要定义它们。AOT编译器在编译时会扫描这些方法,并生成相应的代码。 示例: 假设我们有一个泛型类`MyGenericClass<T>`,其中有一个虚方法`VirtualMethod`。在运行时,我们可能会用不同的类型参数来实例化这个类并调用虚方法。为了避免AOT错误,我们可以创建一个AotStubs脚本: ```csharp using UnityEngine; public class AOTStubs : MonoBehaviour { // 这个方法不会被实际调用,只是为了引导AOT编译器生成代码 private void CreateStubs() { // 为需要预先编译的类型创建存根 var stub1 = new MyGenericClass<int>(); stub1.VirtualMethod(); var stub2 = new MyGenericClass<string>(); stub2.VirtualMethod(); } } ``` 但是请注意,上面的代码中,CreateStubs方法不会被调用,所以编译器可能会优化掉。因此,我们可以使用一个技巧:在Awake或Start中调用一个空方法,但这样会实际运行。更好的做法是使用一个特殊的编译标签,或者确保这个类被包含在构建中。 另一种更常见的做法是使用一个静态构造函数或者一个静态字段的初始化器来触发这些存根: ```csharp public class AOTStubs { // 静态构造函数,确保在运行时之前被调用(在AOT编译时会被处理) static AOTStubs() { // 创建存根实例并调用方法 var stub1 = new MyGenericClass<int>(); stub1.VirtualMethod(); var stub2 = new MyGenericClass<string>(); stub2.VirtualMethod(); } } ``` 但是,静态构造函数在类第一次被使用时才会执行,而AOT编译是在构建时进行的。因此,我们需要确保这个类被包含在构建中。可以将这个脚本挂载到一个在初始场景中存在的游戏对象上,或者使用`[RuntimeInitializeOnLoadMethod]`属性标记一个方法。 然而,更可靠的做法是使用链接器配置文件(link.xml)来保留整个程序集或者类型,同时使用存根脚本触发AOT编译。 另外,Unity提供了一种机制,即使用`AOT.MonoPInvokeCallbackAttribute`来标记需要被AOT编译的回调方法,但这通常用于本地插件调用。 对于泛型虚方法的AOT存根,Unity官方文档建议使用一个预编译步骤,在存根中显式实例化这些泛型类型。 总结步骤: 1. 确定在运行时可能动态生成的代码(如泛型虚方法、通过反射调用的方法等)。 2. 创建一个或多个存根脚本,在这些脚本中显式地创建这些类型的实例并调用可能动态调用的方法。 3. 将这些存根脚本放在一个确保会被编译的位置(比如Editor文件夹外),并且确保在构建时它们会被包含(比如挂载到场景中的物体上,或者使用`[RuntimeInitializeOnLoadMethod]`)。 4. 使用`[Preserve]`属性标记存根类和方法,防止链接器剥离。 5. 构建项目并测试。 注意:有时AOT存根需要针对不同的平台进行不同的处理,但通常iOS平台是最需要关注的。 引用[4]提到了使用`CreateAssetMenu`创建配置文件,这虽然与AotStubs无关,但提醒我们可以使用ScriptableObject来存储配置,但这里不展开。 因此,关于AotStubs的配置,核心就是通过显式代码引导AOT编译器提前编译那些可能动态生成的代码。 相关问题: 1. 如何避免Unity在iOS平台上的AOT编译错误? 2. Unity中如何正确使用反射而不导致AOT错误? 3. 如何配置link.xml文件来防止代码剥离?</think>### Unity AotStubs 脚本详解与配置指南 #### **AotStubs 脚本的核心作用** AotStubs(Ahead-of-Time Stubs)是 Unity 为解决 **AOT 编译限制** 而设计的特殊脚本,主要作用包括: 1. **绕过泛型虚方法限制** iOS 等 AOT 平台禁止 JIT 编译,无法动态生成代码。当使用泛型虚方法时(如 `List<T>.Add()`),AOT 编译器无法预编译所有可能的类型组合,导致运行时错误。AotStubs 通过预生成方法存根解决此问题[^2]。 2. **防止代码剥离错误** Unity 的代码剥离(Code Stripping)可能误删反射调用的方法。AotStubs 显式声明这些方法,确保它们被保留在最终构建中[^2]。 3. **支持跨平台动态代码** 使 IL2CPP 能正确处理动态生成的委托、接口实现等代码,避免 `ExecutionEngineException` 错误[^2]。 --- #### **配置 AotStubs 的 3 种方法** ##### 1. **手动创建存根类**(推荐) 在项目中创建专用存根脚本,显式调用易被剥离的方法: ```csharp // 文件名:AOTStubs.cs public class AOTStubs { // 防止泛型方法被剥离 private void PreserveGenerics() { new System.Collections.Generic.List<int>().Add(0); new System.Collections.Generic.Dictionary<string, object>(); } // 保留反射调用的方法 private void PreserveReflectionMethods() { // 假设通过反射调用 MyClass.ReflectedMethod() typeof(MyClass).GetMethod("ReflectedMethod"); } } ``` **配置要点**: - 将脚本挂载到初始场景的 GameObject 上 - 或在方法添加 `[RuntimeInitializeOnLoadMethod]` 属性[^4] ##### 2. **使用 `link.xml` 文件保留类型** 在 `Assets` 目录创建 `link.xml` 文件,防止特定代码被剥离: ```xml <linker> <assembly fullname="Assembly-CSharp"> <!-- 保留整个命名空间 --> <namespace fullname="MyGame.ReflectionHelpers" preserve="all"/> <!-- 保留特定泛型类 --> <type fullname="MyGame.GenericClass`1" preserve="all"/> </assembly> <!-- 保留第三方库 --> <assembly fullname="Newtonsoft.Json"> <type fullname="Newtonsoft.Json.*" preserve="all"/> </assembly> </linker> ``` ##### 3. **调整 Player Settings** 1. 打开 **Project Settings > Player** 2. 在 **Other Settings** 中: - 设置 **Managed Stripping Level** 为 `Low` 或 `Medium` - 启用 **Use Existing Stripping Database**(Unity 2020+) 3. 在 **Script Compilation** 添加预定义宏: ``` ENABLE_IL2CPP; AOT_ENABLED ``` --- #### **常见问题解决方案** | 问题类型 | 错误示例 | 解决方案 | |---------|----------|---------| | 泛型虚方法 | `ExecutionEngineException` | 在 AotStubs 中实例化泛型类型 | | 反射调用 | `MissingMethodException` | 在 `link.xml` 中保留类型 | | 动态委托 | `NotSupportedException` | 使用 `[MonoPInvokeCallback]` 标记方法 | | 序列化 | `SerializationException` | 添加 `[Serializable]` 并注册类型 | > **最佳实践**:构建 iOS 版本后,检查 `ProjectName/Il2CppOutputProject` 中的编译警告,这些是未处理的 AOT 问题线索[^2]。 --- #### **验证配置是否生效** 1. 打包后检查 Xcode 工程中的 `AOTStubs.cs` 是否包含 2. 在 Unity Editor 中运行 **Assets > Run IL2CPP Code Stripping Analyzer** 3. 使用 **IL2CPP Build Report** 插件分析代码剥离情况 通过合理配置 AotStubs,可显著减少 iOS/Android 平台因 AOT 限制导致的运行时崩溃问题[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值