大家都知道一谈起热更新的话首选是Ulua这个插件, 其实Unity可以使用dll热更新的,如果你实在不想用Lua来编写逻辑,0.0请下看Dll+AssetBundle如何实现热更新的.让你看完这个文章之后只是认识DLL热更新的方式和概念,掌握热更新的实战框架还需要你自己=。=
我们通常的做法是编译成的DLL打成AssetBundle文件, Unity通过WWW下载AB文件获取里面DLL.通过反射的方式把里面的C# 组件绑定到GameObject游戏物体上面,这就是DLL热更新的原理. 假设项目采用UGUI系统, 我们来看看通过以上思想编写代码时候遇到的核心问题如下.
- 我需要如何编写DLL?
- 我的DLL怎么才能获取到UnityEngine命名空间类的引用?
- 我的DLL需要如何打成AssetBundle?
- 程序下载AssetBundle如何读取里面DLL?
- 如何把脚本绑定起来,实现热更新UI?
一、我需要如何编写DLL?
首先你需要找到Unity几个关键DLL. UnityEngine.dll,UnityEngine.UI.dll为了你编写热更新代码有UnityEngine核心类的引用吧.先创建一个C#3.5版本的类库(点击项目右键->属性->目标框架3.5), 然后引入UnityEngine.dll和UnityEngine.UI.dll的DLL
创建完工程之后,我们编写一个MyClass继承MonoBehaviour类
点击启动编译DLL,编译成的DLL可以在项目右键->在文件资源器中打开文件夹->Btn目录->Release和Debug目录找到MyDll.dll(我的是在Realse目录下) 我们把编译好的DLL,拿到Unity里面去打包成AssetBundle文件. Unity默认貌似不允许把后缀名DLL打入AssetBundle,我们修改把MyDll.dll改成MyDll.bytes名字
把DLL打包成AssetBundle文件代码如下,
[MenuItem("Assets/Build Android DLL")] public static void BuildAssetsAndroidDll() { Object mainAsset = AssetDatabase.LoadMainAssetAtPath("Assets/Dll/MyDLL.bytes"); BuildPipeline.BuildAssetBundle(mainAsset, null, Application.dataPath + "\Dll\myassets.android", BuildAssetBundleOptions.None,BuildTarget.Android); if (File.Exists(androidStreamUrl)) { File.Delete(androidStreamUrl); } //拷贝到Stream目录下方便程序下载AB文件 File.Copy(Application.dataPath + "\Dll\myassets.android", androidStreamUrl); }
再来看下我们Unity需要做那些操作,就是新创建一个场景添加一个Text文本即可
给Android下打包好的AssetBundle文件,放入StreamAssetBundleAssets, 代码会自动帮你复制过去
Test核心类
using UnityEngine; using System.Collections; using System.Reflection; using System; using System.IO; using UnityEngine.UI; public class Test : MonoBehaviour { public string url; public string str; public Text myAgeText; public void Awake() { Application.logMessageReceived += Application_logMessageReceived; } void Application_logMessageReceived(string condition, string stackTrace, LogType type) { str += " " + condition; } public void OnGUI() { GUI.Box(new Rect(0, 0, 800, 800), str); } // Use this for initialization IEnumerator Start () { yield return new WaitForSeconds(2); if (Application.platform == RuntimePlatform.WindowsEditor) { url = @"file://"+Application.dataPath + "\Dll\myassets.windows"; }else if(Application.platform == RuntimePlatform.Android) { url = Application.streamingAssetsPath + "/myassets.android"; } else if (Application.platform == RuntimePlatform.IPhonePlayer) { url = Application.streamingAssetsPath + "/myassets.iphone"; } Debug.Log("url: " + url); WWW www = new WWW(url); yield return www; if(www.error != null) { Debug.Log("加载 出错"); } if(www.isDone) { Debug.Log("加载完毕"); AssetBundle ab = www.assetBundle; try { //先把DLL以TextAsset类型取出来,在把bytes给Assembly.Load方法读取准备进入反射操作 Assembly aly = System.Reflection.Assembly.Load(((TextAsset)www.assetBundle.mainAsset).bytes); //获取DLL下全部的类型 foreach (var i in aly.GetTypes()) { //调试代码 Debug.Log(i.Name); str += " " + i.Name; //添加组件到当前GameObject下面 Component c = this.gameObject.AddComponent(i); //然后类名是MyClass,就把文本引用赋值给MyClass.platefaceText属性. if (i.Name == "MyClass") { FieldInfo info = c.GetType().GetField("platefaceText"); info.SetValue(c, myAgeText); } } } catch (Exception e) { Debug.Log("加载DLL出错"); Debug.Log(e.Message); } } } }
在Windows下查看效果图
以上只是一个抛砖引玉,希望想使用dll热更新代码的能帮助到你.
项目下载地址: http://yunpan.cn/cmE4eL5948ghQ 访问密码 df6b