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

[笔记] 【专栏精选】Unity热更新之ILRuntime

[复制链接]
发表于 2020-12-15 09:27 | 显示全部楼层 |阅读模式
本文节选自洪流学堂公众号技术专栏《大话Unity2019》,未经允许不可转载。
洪流学堂公众号回复专栏,查看更多专栏文章。
洪流学堂,让你快人几步。你好,我是郑洪智。

logo.png
小新:“热更新真的是打开了一片天啊,现在我越发感觉热更新能做的事情太多了。之前做了一个项目,每次打包都好花费半小时,如果有热更新,只需要替换一下dll就行了。”
大智:“没错,热更新可以大幅提高迭代效率,更能提高用户体验。”
小新:“那之前还提到了几个能兼容全平台的方案,我们也来学一学吧?”
大智:“那你可需要做好心理准备了,能兼容全平台的方案在学习曲线上都比较陡峭,不像前两天通过dll实现热更新时那么简单。”
小新:“那怕啥,这么多风风雨雨都走过来了,嘿嘿”
大智:“兼容全平台的热更新方案主要有两类C#类和lua类,lua还需要额外掌握lua语言。我们今天继续学习和C#联系更紧密的一种热更新方案,那就是ILRuntime。”
ILRuntime

ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新。
ILRuntime的下载地址是:
ILRuntime源码
ILRuntime Unity Demo
ILRuntime的优势

同市面上的其他热更方案相比,ILRuntime主要有以下优点:
    无缝访问C#工程的现成代码,无需额外抽象脚本API直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL执行效率是L#的10-20倍选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口)支持跨域继承完整的泛型支持拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017
估计现在上面的有些优点你还不太明白,你只需要知道ILRuntime的优点很多就是啦,等后面我们学习了其他的热更新方案你可以亲自回来比较一下。
从0开始

学习一个新东西,我们首先需要看的就是文档和示例源码。
首先我们将Unity Demo的源码下载下来:ILRuntime Unity Demo
Unity工程

下载完后使用Unity打开,会有很多很多的报错,不用担心,你会看到错误的原因都是一样的,我们根据报错的提示进行修复。
  1. Assets\Scripts\Examples\11_ValueTypeBinding\QuaternionBinder.cs(12,21): error CS0227: Unsafe code may only appear if compiling with /unsafe. Enable "Allow 'unsafe' code" in Player Settings to fix this error.
复制代码
最后一句,在Player Settings里面勾选Allow 'unsafe' code 可以修复这个错误。


如图勾选
这一步做完后,工程中就只剩下warning了,我们先忽略这些warning。
dll工程

dll工程打开前一定要先打开一次Unity目录,用来生成dll文件,否则会有很多报错。
如果UnityEngine.dll找不到,可以手动设置。在Unity2018.3中,需要引入UnityEngine.CoreModule.dll,我的路径在这,方便你去找:C:\Program Files\Unity\Hub\Editor\2018.3.8f1\Editor\Data\Managed\UnityEngine\
如果还有报错,需要把Hotfix_Project的属性改成4.x,不超过4.6,因为目前IL官方声明支持到4.6。




Unity目录结构

我们先看一下示例工程的目录结构:






    _Scenes:示例场景ILRuntime、LitJson、Mono.Cecil.20、Mono.Cecil.Pdb:这些都是ILRuntime库的相关文件夹Scripts:这个Demo相关的代码StreamingAssets:Unity的特殊目录,动态加载gmcs、link、smcs:ILRuntime的一些配置文件(Unity新版本中将gmcs和smcs合并为csc.rsp文件,用于配置一些预编译命令。先前的Allow 'unsafe' code错误也可以通过将smcs.rsp文件重命名为csc.rsp文件解决。)
1. HelloWorld

我们先来看下_Scenes/Examples/01_HelloWorld。
这里面主要的逻辑在一个代码文件中,和我们之前使用dll进行热更新时有些类似,我们来仔细分析一下。
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.IO;
  4. using ILRuntime.Runtime.Enviorment;
  5. public class HelloWorld : MonoBehaviour
  6. {
  7.     //AppDomain是ILRuntime的入口,最好是在一个单例类中保存,整个游戏全局就一个,这里为了示例方便,每个例子里面都单独做了一个
  8.     //大家在正式项目中请全局只创建一个AppDomain
  9.     AppDomain appdomain;
  10.     void Start()
  11.     {
  12.         StartCoroutine(LoadHotFixAssemby());
  13.     }
  14.     IEnumerator LoadHotFixAssembly()
  15.     {
  16.         //首先实例化ILRuntime的AppDomain,AppDomain是一个应用程序域,每个AppDomain都是一个独立的沙盒
  17.         appdomain = new AppDomain();
  18.         //正常项目中应该是自行从其他地方下载dll,或者打包在AssetBundle中读取,平时开发以及为了演示方便直接从StreammingAssets中读取,
  19.         //正式发布的时候需要大家自行从其他地方读取dll
  20.         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  21.         //这个DLL文件是直接编译HotFix_Project.sln生成的,已经在项目中设置好输出目录为StreamingAssets,在VS里直接编译即可生成到对应目录,无需手动拷贝
  22. #if UNITY_ANDROID
  23.         WWW www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.dll");
  24. #else
  25.         WWW www = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.dll");
  26. #endif
  27.         while (!www.isDone)
  28.             yield return null;
  29.         if (!string.IsNullOrEmpty(www.error))
  30.             UnityEngine.Debug.LogError(www.error);
  31.         byte[] dll = www.bytes;
  32.         www.Dispose();
  33.         //PDB文件是调试数据库,如需要在日志中显示报错的行号,则必须提供PDB文件,不过由于会额外耗用内存,正式发布时请将PDB去掉,下面LoadAssembly的时候pdb传null即可
  34. #if UNITY_ANDROID
  35.         www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.pdb");
  36. #else
  37.         www = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.pdb");
  38. #endif
  39.         while (!www.isDone)
  40.             yield return null;
  41.         if (!string.IsNullOrEmpty(www.error))
  42.             UnityEngine.Debug.LogError(www.error);
  43.         byte[] pdb = www.bytes;
  44.         using (MemoryStream fs = new MemoryStream(dll))
  45.         {
  46.             using (MemoryStream p = new MemoryStream(pdb))
  47.             {
  48.                 appdomain.LoadAssembly(fs, p, new Mono.Cecil.Pdb.PdbReaderProvider());
  49.             }
  50.         }
  51.         InitializeILRuntime();
  52.         OnHotFixLoaded();
  53.     }
  54.     void InitializeILRuntime()
  55.     {
  56.         //这里做一些ILRuntime的注册,HelloWorld示例暂时没有需要注册的
  57.     }
  58.     void OnHotFixLoaded()
  59.     {
  60.         //HelloWorld,第一次方法调用
  61.         appdomain.Invoke("HotFix_Project.InstanceClass", "StaticFunTest", null, null);
  62.     }
  63.     void Update()
  64.     {
  65.     }
  66. }
复制代码
看完上面的代码你发现了什么?
和我们前两天学习的使用dll热更新的代码神相似,对不对?
总结

大智:“ILRuntime就是实现了一个运行时,绕过了iOS的限制。这样我们在使用的时候,你会发现和我们前两天学习的dll热更新基本是一致的。”
今日思考题

大智:“将前两天学习的内容,使用ILRuntime实现看看,会不会遇到什么问题?”
小新:“好嘞!”
大智:“收获别忘了分享出来!也别忘了分享给你学Unity的朋友,也许能够帮到他。”
洪流学堂公众号回复专栏,查看更多专栏文章。

本帖子中包含更多资源

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

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

本版积分规则

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

GMT+8, 2024-12-23 12:13 , Processed in 0.092943 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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