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

Uma*_*r M 3 c# performance android unity-game-engine

我正在尝试减少从Unity构建的APK的大小.看看Android Player设置文档,我发现我可以使用以下选项之一来减少构建的大小:

剥离级别:

  1. 带组件
  2. Strip ByteCode(仅限iOS)
  3. 使用micro mscorlib
  4. 剥离引擎代码(仅在使用IL2CPP时可用)

我有以下问题:

IOS Build Size Optimization中,它说:

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

它也适用于Android吗?

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

剥离应用于.dllVisual Studio/MonoDevelop无法访问的第三方代码吗?

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

更新:

我在android项目中尝试了IL2CPP,它增加了10MB的aprox来构建大小并且花了很长时间来构建.

谢谢

Jos*_*son 9

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

TL; DR:如果您在优化建筑面积,然后用单声道与"地带大会"是最好的选择.

编译选项

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

  1. 即时(JIT)编译
  2. 提前(AOT)编译

JIT编译发生在Mono脚本后端.项目中的托管代码被编译为IL字节代码,并作为IL程序集发送给最终用户.IL程序集被编译为用户设备上的本机机器代码.

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

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

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

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

剥离选项

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

  1. 托管代码剥离
  2. 引擎代码剥离

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

剥离应用于Visual Studio/MonoDevelop中无法访问的第三方.dll代码吗?

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

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

编译和剥离

编译和剥离选项交叉如下:

  • 单声道脚本后端
    • 默认是没有托管或引擎代码剥离
    • Strip Assemblies导致托管代码剥离和启用引擎代码剥离.
  • IL2CPP脚本后端
    • 始终启用托管代码剥离.
    • 发动机代码剥离是可选的.

编译,剥离和反思

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

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

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

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

由于您已经检查了项目中的代码,因此您可以相对自信,但如果不运行项目中的所有代码路径,就无法证明事情是否有效.

  • 运行时性能实际上取决于项目的性质.对于受脚本代码执行约束的项目,使用IL2CPP进行AOT编译代码会带来很好的性能提升.对于图形界限的项目,改进通常不会那么大.此外,Android设备的硬件特性差异很大.所以我不能给出一般答案. (2认同)