如何在Android Player设置Unity中使用剥离级别/ IL2CPP选项

时间:2016-12-11 14:28:37

标签: c# android performance unity3d

我正在尝试减少从Unity构建的APK的大小。看看Android播放器设置docs,我发现我可以使用以下选项之一来减少构建的大小:

剥离级别:

  1. 条带装配
  2. Strip ByteCode(仅限iOS)
  3. 使用micro mscorlib
  4. 剥离引擎代码(仅在使用IL2CPP时可用)
  5. 我对此有以下问题:

    IOS Build Size Optimization中说:

      

    剥离程序集级别:分析脚本的字节码,以便进行分析   未从脚本引用的类和方法可以是   从DLL中删除,从而从AOT编译中排除   相。这种优化减少了主二进制文件的大小   附带的DLL和只要不使用反射就是安全的

    它也适用于Android吗?

    如果是这样的话,我试图在整个项目中找到System.Reflection的引用(包括第三方插件)。我只能在#if UNITY_EDITOR下的Edior脚本或脚本中看到反射的用法。如何确保剥离不会导致android构建中出现任何问题?

    是否在第三方.dll代码上应用了剥离,这些代码在Visual Studio / MonoDevelop中无法访问?

    IL2CPP或剥离级别的使用是否以任何方式影响应用程序的性能?

    更新

    我在android项目中尝试了IL2CPP,它在构建大小时增加了10MB的aprox,并且还需要很长时间才能构建。

    由于

1 个答案:

答案 0 :(得分:9)

是的,关于剥离的iOS Build Size Optimization信息也适用于Android。这里有一些你需要注意的权衡。

TL; DR:如果您只针对构建大小进行优化,那么使用Mono和“Strip Assemblies”是最佳选择。

编译选项

当然,有一些微妙的问题可能对您的案件很重要。对于Android,Unity提供两种不同的编译模式。

  1. 即时(JIT)编译
  2. 提前(AOT)编辑
  3. 使用Mono脚本后端发生

    JIT编译。项目中的托管代码被编译为IL字节代码,并作为IL程序集发送给最终用户。 IL程序集将编译为用户设备上的本机机器代码。

    使用IL2CPP脚本后端发生

    AOT编译。项目中的托管代码编译为IL字节代码,然后转换为C ++代码,然后在您的机器上编译为本机代码。该本机机器代码将发送给最终用户并在用户设备上运行。

    在几乎所有情况下,IL字节代码都比本机代码更紧凑,因此使用Mono脚本后端的APK大小会更小。

    此外,Mono脚本后端在构建过程中对您的计算机执行的工作较少,因此项目构建将更快。

    最后,IL2CPP脚本后端默认构建两个本机二进制文件,一个用于armv7,另一个用于x86。如果您不需要支持x86,可以更改播放器设置以仅构建其中一个(可能是armv7)。

    剥离选项

    Unity执行两种不同类型的剥离:

    1. 托管代码剥离
    2. 引擎代码剥离
    3. 托管代码剥离是在托管编译器运行后在托管程序集上执行的,但在将任何代码打包到APK之前。此过程使用一组已知的根(如项目中从MonoBehaviour派生的任何类),并构建可以被证明调用的所有代码的依赖关系图。任何无法被证明调用的IL代码都将从IL程序集中删除,并且不会成为APK的一部分。

        

      是否在第三方.dll代码上应用了剥离,这些代码在Visual Studio / MonoDevelop中无法访问?

      此过程适用于项目中的所有托管程序集(.dll文件)。

      引擎代码剥离导致本机引擎代码中的子系统在项目构建过程结束时被本机链接器删除。例如,如果启用了引擎代码剥离,并且您的项目不使用任何3D物理特性,则3D物理系统不应包含在最终的APK中。

      编译和剥离

      编译和剥离选项如下所示:

      • 单声道脚本后端
        • 默认不是托管或引擎代码剥离
        • Strip Assemblies会导致托管代码剥离并启用引擎代码剥离。
      • IL2CPP脚本后端
        • 托管代码剥离始终启用。
        • 引擎代码剥离是可选的。

      编译,剥离和反射

      由于IL2CPP脚本后端仅为AOT,因此不支持System.Reflection.Emit命名空间。对它的任何调用都会在运行时抛出NotSupportedException

      Mono确实支持System.Reflection.Emit命名空间,但您必须小心使用它,并启用托管代码剥离的System.Reflection命名空间。由于托管代码剥离器无法静态证明只能访问的代码是使用反射,因此剥离器将删除该代码。

        

      如何确保剥离不会导致android构建中的任何问题?

      了解这一点的唯一好方法是运行时测试。在运行之前,无法确定剥离器是否过于激进并删除代码。

      由于您已经检查了项目中的代码,因此您可以相对自信,但如果不运行项目中的所有代码路径,就无法证明事情能够正常工作。