Unity将来时:IL2CPP怎么用?

版本准备

前文详细的介绍了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


欢迎关注IndieACE微信公众号:IndieAce,可以看到IndieACE定期分享的好内容。

需要转载IndieACE的文章请与我们私信联系。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
淘宝花钱买的最新版!需要的拿去! This asset obfuscates your code to make it harder for bad guys to reverse engineer your projects. Specifically designed for Unity, it seamlessly links in with its build process. The top priority of this package is to work straight out of the box with no extra steps required. While other obfuscators can stop a game from working, Beebyte's obfuscator looks for specific Unity related code that must be protected. The contents of your source files are unchanged, the obfuscation targets the compiled assembly. Features: - Supports IL2CPP - Supports Assembly Definition Files (Unity 2017.3+) - Removes Namespaces without any conflicts - Recognises Unity related code that must not be changed - Renames Classes (including MonoBehaviours) - Renames Methods - Renames Parameters - Renames Fields - Renames Properties - Renames Events - String literal obfuscation - Adds fake methods - Easy and extensive customisation using the Unity inspector window - Consistent name translations are possible across multiple builds and developers - Semantically secure cryptographic naming convention for renamed members The asset works for both Unity Free and Unity Pro version 4.2.0 onwards (including Unity 5 & 2017 & 2018). Build targets include Standalone, Android, iOS, WebGL, UWP. Other platforms are not guaranteed or supported but may become supported at a future date. IL2CPP builds are much harder to reverse engineer but strings and member information (class, method names etc) are visible in the global-metadata.dat file. Obfuscation will apply to this file adding further security. Why not complement your security with the Anti-Cheat Toolkit - a great third party asset. For more information about the Obfuscator, please see the FAQ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值