转载请标明出处:http://www.cnblogs.com/zblade/
对于游戏中的热更,目前主流的解决方案,分为Lua(ulua/slua/xlua/tolua)系和ILRuntime代表的c#系。今天就来探究一下ILRuntime是如何实现热更的流程的,新手入门,个中有错误理解,欢迎指正。
ILRuntime的原理
首先说一下lua的热更新基本过程,unity提供了AssetBundle的资源打包方式,这样可以通过资源的对比来更新最新的资源。而lua文件不需要编译,可以被打包进游戏的资源中,在游戏启动的过程中加载对应的脚本资源,今儿解释执行转换为字节码,在lua的虚拟机中执行,这种天然的设计,可以规避静态语言需要编译的环节。
C#代码在编写后,是需要执行编译的,才能起效,这样如果在手机端,没有对应的编译环境,那么对应的c#代码就无法实现热更。ILRuntime实现的基础,也是基于AssetBundle的资源热更新方式,将需要热更新的c#代码打包成DLL,放在工程的StreamingAssets下,在每次完成资源打包后,对应的DLL会被作为资源热更新出去。这样就规避了编译相关的环节,实现了热更。
文字讲述较为枯燥,看看示例代码是如何执行这个流程的:
1、ILRuntime的相关资料链接
可以在github上查找: ILRuntime
对应的unity3d的工程的例子:ILRuntime U3D例子
2、探究ILRuntime的例子
整个例子分为两个部分:
分别是热更新的工程和U3D主工程,那么先看看U3D工程:
较为重要的是两个部分,一个是ILRuntime需要用到的几个环境,重点是Mono.Ceil.20, Mono.Ceil.Pdb,ILRuntime三个文件夹,ILRuntime后续的版本将LitJson也加入进来了。
另一个关键点就是讲HotFix_Project.dll作为资源加入到StreamingAssets文件夹下,这样就可以被ab打包作为资源热更新出去。
接下来我们打开HotFix_Project:
得到的工程为:
重点分析一下引用,可以看到,该工程是引用了UnityEngine/UnityEngine.UI/Assembly-CSharp等几个U3D游戏主工程中的dll的,这样,可以在工程中直接调用对应的u3d相关的dll下的类和方法,示例代码:
只要using UnityEngine申明后,下面的代码就可以继承MonoBehaviour类,自然可以调用其中的相关类和方法。那么到这一步,就可以理解,在HotFix_Project中,我们是可以调用U3D游戏主工程的类和方法的,只要添加其相关的dll到工程的引用中。这样我们就完成了HotFix对U3D游戏主工程的调用的一条线路。
3、U3D游戏主工程调用HotFix_Project中的类型和相关方法
现在的调用都是交互式的,在完成了hotfix对u3d的调用后,我们接下来看看u3d是如何调用hotfix中的类和方法的。
取我们最常见和关注的反射作为一个示例,这样可以了解整个调用过程。
首先,需要加载hotfix的dll,来看看相关的代码:
整个竖屏截出来的图比较大,跟随箭头来看看流程:
1) 首先MonoBehaviour下的Start执行一个协程;
2) 实例化唯一的appdomain;
3) 加载hotfix的dll和pdb,可以看到,如果我们热更新相关的dll和pdb,是需要在这一步之前执行的,其实可以放在Awake中执行,当然这儿没有热更,我们就直接执行dll和pdb的加载;
4) 在完成dll和pdb的加载后,执行assembly的加载,这样我们可以获取到hotfix中的相关类和方法,属性等相关信息,相关可以查看源码即可了解。
5) 测试如何调用反射:
Debug.Log("热更DLL中的类型我们均需要通过AppDomain取得"); var it = appdomain.LoadedTypes["HotFix_Project.InstanceClass"]; Debug.Log("LoadedTypes返回的是IType类型,但是我们需要获得对应的System.Type才能继续使用反射接口"); var type = it.ReflectionType; Debug.Log("取得Type之后就可以按照我们熟悉的方式来反射调用了"); var ctor = type.GetConstructor(new System.Type[0]); var obj = ctor.Invoke(null); Debug.Log("打印一下结果"); Debug.Log(obj); Debug.Log("我们试一下用反射给字段赋值"); var fi = type.GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); fi.SetValue(obj, 111111); Debug.Log("我们用反射调用属性检查刚刚的赋值"); var pi = type.GetProperty("ID"); Debug.Log("ID = " + pi.GetValue(obj, null));
让我们看看整个流程:
基于appdomain来获取类,然后获取type,对应的invoke, 也可以利用反射来修改对应的field的值。
总结:到这儿,我们就基本理清楚了基于ILRuntime如何实现hotfix和u3d主工程之间的相互调用,可以讲这样一套热更新方式嵌套到游戏的框架中,实现不用lua来实现热更。当然ILRuntime要转换到IL2CPP,还是有很多地方需要注意的,详情可以参考github上的相关手册。