(IL2CPP下篇) Unity将来时:IL2CPP怎么用?

    xiaoxiao2021-03-25  81

    转自:https://zhuanlan.zhihu.com/p/19972666

    版本准备

    前文详细的介绍了IL2CPP的来龙去脉,这里用一个实际的例子来看看Unity3D里的IL2CPP都为我们做了哪些工作以及在使用的过程中会遇到哪些问题。

    IL2CPP应用的第一个平台是WebGL,为了让游戏可以一键部署到基于WebGL的浏览器中,Unity3D Script工作组的大牛们找到了一个绝妙的解决方案:不仅解决了C#,Unity Script语言兼容问题,还解决了客户端源码泄漏问题。这个功能在Unity5.0 Beta版中提供了测试。 IL2CPP的第二个试用平台是iOS 64位版。大家都知道苹果已经发了最后通牒,全新App必须在15年2月1日支持64位CPU,而已经上架的游戏也必须在15年6月1日更新的时候支持64位。这个64位编译就是交由IL2CPP完成的。具体到版本是 Unity 4.6.1 p5,Unity4.6.2和Unity 4.6.2 p1。本文后面都使用4.6.2 p1版本来进行演示。 创建项目,加入代码 创建一个空的项目,加入两个cs文件,一个叫IL2CPPCompatible.cs,另外一个是IL2CPPStudy.cs。前者主要用来测试代码在IL2CPP中的兼容性,后者用来产生C++代码,用来做对比分析。 以下是两个文件的详细内容:

    IL2CPPCompatible.cs

    这个文件中有两个兼容性测试函数。一个函数使用ThreadPool.QueueUserWorkItem启动一个新的线程。另一个则是SSL认证函数:ssl.AuthenticateAsClient (hosturl); 之所以写这两个函数是因为上述4.6.x IL2CPP对他们支持的还不是很好,会产生问题,这个我们在后面会详细讲到。

    IL2CPPStudy.cs

    using UnityEngine; using System.Collections; using System.IO; using System.Threading; public class CoconutClassStudy { public int inta; public int intb; public int Add() { return inta + intb; } public CoconutClassStudy(int a, int b) { inta = a; intb = b; } public void IOTest(string filename) { if (File.Exists (filename)) { FileStream fs = File.Open(filename, FileMode.Create); fs.Close(); } } public void ThreadTest() { Thread a =new Thread(delegate(object state) { Debug.Log ("Thread Started"); }); a.Start (); } } public class IL2CPPStudy : MonoBehaviour { // Use this for initialization void Start () { Debug.Log (CoconutFuncStudy (10 , 20)); CoconutClassStudy cc = new CoconutClassStudy (50, 60); Debug.Log (cc.Add ()); cc.IOTest("test.txt"); cc.ThreadTest (); Debug.Log (cc.GetType ()); } // Update is called once per frame void Update () { } int CoconutFuncStudy(int a, int b) { return a + b; } } 这个文件里面的内容就更简单了:一个CoconutClassStudy类,里面有一个构造函数,一个Add函数和一个IOTest函数。另外在MonoBehaviour的Start()中,创建这个类的实例,并调用这两个函数。这个源码可以让我们研究以下几个方面: 1.cs的类在经过IL2CPP以后如何在CPP文件中表达 2.C#的IO操作经过IL2CPP以后如何在CPP文件中表达 3.当调用new关键字在堆里产生一个实例的时候CPP文件又是如何做的 4.开启一个线程的操作IL2CPP会如何翻译 5.调用cc.GetType()的行为IL2CPP如何处理

    有了这连个文件后我们要做的第一件事情是生成XCode项目: 选择IL2CPP编译模块,然后Build,生成XCode项目。 打开项目,在项目结构中打开Classes目录,可以看到多了一个Native的子目录。 IL2CPP转换出的所有文件都在其中。 我们写的逻辑代码,都在Assembly-CSharp.cpp中,除了这个文件,Native文件夹中还有很多以Bulk开头的文件,这些其实是IL2CPP把一些必要C#库翻译到CPP形成的文件。

    像Bulk_Generics_x.cpp和System.Collections.Generic有关。 Bulk_UnityEngine.UI_x.cpp则和Unity自带的UI有关。 让我们粗略的分析下在CPP文件中前面的5条都是如何实现的: 1.cs的类在经过IL2CPP以后如何在CPP文件中表达 我们的CoconutClassStudy类在CPP文件中变成了一个Struct,继承于Object_t4。那这个Object_t4又是什么呢? 聪明的你一看注释就知道了吧,没错,这个就是C#中的万物之源,System.Object。 既然我们C#的类变成了Struct,那类里面的函数都去哪里了呢?带着这个疑问,我们来看第二条。 2.C#的IO操作经过IL2CPP以后如何在CPP文件中表达 在CoconutClassStudy类中有一个成员函数:IOTest。在CPP中,我们看到了如下的实现: 类中的函数变成了一般的全局函数,函数名字是类名加上函数名,最后加上一个后缀而成。而原本C#中的File.Exists和File.Open函数都有了相应的C++实现。 3.当调用new关键字在堆里产生一个实例的时候CPP文件又是如何做的? C#代码中我们在Start函数中有一个显示的New,找到相应C++代码: 可以看到代码调用了一个叫il2cpp_codegen_object_new的函数。而这个函数最终调用了IL2CPP VM中的New函数,分配了属于GC管理的内存。 接下来第四条 4.开启一个线程的操作IL2CPP会如何翻译 C#中的System.Thread,在C++中是一个Thread_t26相当巨大的结构,在New出了这个结构之后,设置线程入口函数,最后调用Thread_Start_m47启动线程。这个函数就是对应System.Threading.Thread.Start()  我们看最后一条 5.调用cc.GetType()的行为IL2CPP如何处理。找到C++中的对应Start函数: 首先我们看到了对应C#中的Type的C++实现:Type_t28,其次是GetType()这个函数在C++中的实现,最后发现是调到了IL2CPP的VM函数: 在这些C++的实现中,细心的读者可能会发现他们时时刻刻都在使用MethodInfo和TypeInfo这样的信息。这个就是Unity Script项目组提到的Metadata。Metadata指的是非逻辑代码,而是函数,结构,变量以及类本省的一些信息。比如名字,类型等。这个Metadata提供C++代码和后台的IL2CPP VM运行时必要的信息。 以上5条只是很简单的例子,大家如果对IL2CPP的转换感兴趣,可以自己写出想要了解的测试代码,然后再对比CPP文件看其实现。 前方有坑,请小心 新的事物总是伴随着问题,特别是在软件行业,Bug是不可避免的。就目前阶段而言,IL2CPP还有不少问题。这个就是项目中IL2CPPCompatible.cs存在的意义:做兼容性测试。大家在实际的项目中如果遇到了问题,可以在这个文件中追加测试代码。下面的表格把我们遇到的已知问题做一个列举,供参考。 IL2CPP总结以及我们的建议 IL2CPP是Unity核心进行的很重要的进化之一。就现在来看,好处有以下几点: 1.运行速度加快,游戏安装尺寸减小,内存占用降低 2.除了可以Mono调试C#之外,我们又多了一种选择:Native C++ 源码级调试(不知道你们什么感觉,我对Unity C#调试颇有意见,经常连不上调试器,而且调试过程中常常宕机。换成用原生IDE调试C++代码,就爽很多啦)。 3.可以快速的支持新的平台,当然这点对我们关系不大。 带来的问题: 1.由于原来由Mono VM的IL代码全部变成了CPP,导致项目中多了很多CPP代码,编译时间会显著增加。 2.IL2CPP还有各种Bug,可能会导致原来的代码不能很好的编译运行。需要等待Unity版本迭代。 3.鉴于C++静态语言的特性,我们不能使用诸如System.Reflection.Emit这样的动态代码。(C# ATO方式编译) 给使用Unity开发者的建议: IL2CPP是大势所趋,加上苹果强制使用64位支持,意味着到了6月1号,所有用Unity开发的游戏都要用到新的编译方式。如果你的项目比较大,应该立刻开始尝试IL2CPP,以便发现问题,并开始解决。 本文项目在: CoconutIslandStudio/IL2CPP_Test · GitHub
    转载请注明原文地址: https://ju.6miu.com/read-36350.html

    最新回复(0)