找回密码
 立即注册
查看: 444|回复: 0

Unity之IL2CPP

[复制链接]
发表于 2020-12-16 09:15 | 显示全部楼层 |阅读模式
作者:罗鹏

背景

在Unity4.6.1 p5以后版本中,在PlayerSettings—>Other Settings—>Scripting Backend有mono和il2cpp两个选项,它们是Unity脚本后处理(Scripting Backend)的两种方式。
概念

IL2CPP 是 Unity一种新的脚本后处理(Scripting Backend)方式,针对.Net平台编译输出的IL(中间语言)进行处理。
IL2CPP主要由两部分组成:
    AOT静态编译编译器(il2cpp.exe)运行时库(libil2cpp)
其中AOT将IL转换为C++源码,再交给各平台的C++编译器进行编译,达到平台兼容的目的;运行时库则会提供诸如垃圾回收、线程/文件获取、内部调用直接修改托管数据结构的原生代的服务与抽象。
对比

Mono
    构建应用非常快。由于Mono的JIT(Just In Time compilation)机制,所以支持更多托管类库。支持运行时代码执行。必须将代码发布成托管程序集(.dll文件,由mono或者.net生成)。Mono VM在各个平台移植异常麻烦,有几个平台就得移植几个VM(WebGL和UWP这两个平台只支持 IL2CPP)。Mono版本授权受限,C#很多新特性无法使用。iOS仍然支持Mono,但是不再允许Mono(32位)应用提交到Apple Store。
IL2CPP
相比Mono,代码生成有很大的提高。
    可以调试生成的C ++代码。可以启用引擎代码剥离(Engine code stripping)来减少代码的大小。程序的运行效率比Mono高,运行速度快。多平台移植非常方便。相比Mono构建应用慢。只支持AOT(Ahead of  Time)编译。
AOT编译器

IL2CPP AOT编译器实际的执行文件是il2cpp.exe。在Windows平台你可以在Unity安装路径的Editor\Data\il2cpp目录下找到。对于OSX平台,它位于Unity安装路径的Contents/Frameworks/il2cpp/build目录内。 il2cpp.exe这个工具是一个托管代码可执行文件,其完全由C#写成。在开发IL2CPP的过程中,我们同时使用.NET和Mono编译器对其进行编译。
IL2CPP打包注意事项

由于IL2CPP的运行效率的大幅度优势,我们在实际项目中几乎都是直接使用IL2CPP的,在打包过程中可能会遇到一些问题。
IL2CPP和mono的最大区别就是不能在运行时动态生成代码和类型,所以这就要求必须在编译时就完全确定需要用到的类型。
类型裁剪
IL2CPP在打包时会自动对Unity工程的DLL进行裁剪,将代码中没有引用到的类型裁剪掉,以达到减小发布后ipa包的尺寸的目的。然而在实际使用过程中,很多类型有可能会被意外剪裁掉,造成运行时抛出找不到某个类型的异常。特别是通过反射等方式在编译时无法得知的函数调用,在运行时都很有可能遇到问题。
Unity提供了一个方式来告诉Unity引擎,哪些类型是不能够被剪裁掉的。具体做法就是在Unity工程的Assets目录中建立一个叫link.xml的XML文件,然后按照下面的格式指定你需要保留的类型:
  1. <linker>
  2.   <assembly fullname="UnityEngine" preserve="all"/>
  3.   <assembly fullname="Assembly-CSharp">
  4.     <namespace fullname="MyGame.Utils" preserve="all"/>
  5.     <type fullname="MyGame.SomeClass" preserve="all"/>
  6.   </assembly>  
  7. </linker>
复制代码
泛型实例
每个泛型实例实际上都是一个独立的类型,List<A>和 List<B>是两个完全没有关系的类型,这意味着,如果在运行时无法通过JIT来创建新类型的话,代码中没有直接使用过的泛型实例都会在运行时出现问题。
这个问题有两种方式,一个是使用CLR绑定,把用到的泛型实例都进行CLR绑定。另外一个方式是在Unity主工程中,建立一个类,然后在里面定义用到的那些泛型实例的public变量。这两种方式都可以告诉IL2CPP保留这个类型的代码供运行中使用。
泛型方法
跟泛型实例一样,foo.Bar<TypeA>和foo.Bar<TypeB>是两个完全不同的方法,需要在主工程中显式调用过,IL2CPP才能够完整保留,因此需要尽量避免在热更DLL中调用Unity主工程的泛型方法。如果在iOS上实际运行遇到报错,可以尝试在Unity的主工程中随便写一个static的方法,然后对这个泛型方法调用一下即可,这个方法无需被调用,只是用来告诉IL2CPP我们需要这个方法。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-28 22:27 , Processed in 0.106184 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表