Windows-->package Manager,找到ILRuntime
如果找不到,配置一下根目录的manifest.json,文件头部增加
================
{
"scopedRegistries": [
{
"name": "ILRuntime",
"url": "https://registry.npmjs.org",
"scopes": [
"com.ourpalm"
]
}
],
"dependencies": {
"com.ourpalm.ilruntime": "2.1.0-preview.1",
"com.unity.2d.animation": "5.0.7",
"com.unity.2d.pixel-perfect": "4.0.1",
===================
引入之后在Asset目录下会多一个Sample,打开目录下有sln结尾的工程文件,vs或者Rider打开
新建cs文件,测试
namespace HotFix_Project.HotFixTest
{
//Helloworld
public class HotFixHelloWorld
{
private static void HelloWorld()
{
UnityEngine.Debug.Log("HotPro:HelloWorld!!");
}
private static string HotStaticMethodWithString(string para)
{
UnityEngine.Debug.Log("HotPro:HotStaticMethodWithString!!"+para);
return "HotPro:return HotStaticMethodWithString!!";
}
private string HotCallMethodWithString()
{
UnityEngine.Debug.Log("HotPro:HotCallMethodWithString!!");
return "HotPro:return HotCallMethodWithString!!";
}
}
}
编译没问题,在Assets目录创建StreamingAssets文件,构建生成热更新项目,会生成dll文件到该目录
项目里创建初始化单例
using System;
using System.IO;
using UnityEngine;
using AppDomain = ILRuntime.Runtime.Enviorment.AppDomain;
namespace Merge_County.Scripts.ILRuntimeFramework
{
public class HotFixMgr : MonoBehaviour
{
//AppDomain是ILRuntime的入口,最好是在一个单例类中保存,整个游戏全局就一个,这里为了示例方便,每个例子里面都单独做了一个
//大家在正式项目中请全局只创建一个AppDomain
private static HotFixMgr _mInstance;
// ReSharper disable Unity.PerformanceAnalysis
public static HotFixMgr GetInstance()
{
if (_mInstance == null)
{
_mInstance = new GameObject("HotFixMgr").AddComponent<HotFixMgr>();
_mInstance.LoadILRuntime();
_mInstance.InitILRuntime();
}
return _mInstance;
}
public AppDomain Appdomain;
private MemoryStream _fs;
private MemoryStream _p;
private readonly Boolean _isServer = false;
private void InitILRuntime()
{
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)
//unity的Profiler接口只允许在主线程使用
Appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif
//注册CLR绑定,避免过多的反射访问,提升性能
ILRuntime.Runtime.Generated.CLRBindings.Initialize(Appdomain);
Appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((act)=>
{
return new UnityEngine.Events.UnityAction(() =>
{
((Action)act).Invoke();
});
});
Appdomain.DelegateManager.RegisterFunctionDelegate<Int32>();
Appdomain.DelegateManager.RegisterDelegateConvertor<DG.Tweening.Core.DOSetter<Int32>>((act) =>
{
return new DG.Tweening.Core.DOSetter<Int32>((pNewValue) =>
{
((Action<int>)act)(pNewValue);
});
});
Appdomain.DelegateManager.RegisterDelegateConvertor<DG.Tweening.Core.DOGetter<Int32>>((act) =>
{
return new DG.Tweening.Core.DOGetter<Int32>(() => ((Func<int>)act)());
});
Appdomain.DelegateManager.RegisterFunctionDelegate<Single>();
Appdomain.DelegateManager.RegisterDelegateConvertor<DG.Tweening.Core.DOSetter<Single>>((act) =>
{
return new DG.Tweening.Core.DOSetter<Single>((pNewValue) =>
{
((Action<Single>)act)(pNewValue);
});
});
Appdomain.DelegateManager.RegisterDelegateConvertor<DG.Tweening.Core.DOGetter<Single>>((act) =>
{
return new DG.Tweening.Core.DOGetter<Single>(() =>
{
return ((Func<Single>)act)();
});
});
}
private void LoadILRuntime()
{
Appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();
//#if UNITY_ANDROID
//WWW www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.dll");
//#else
WWW www = new WWW("");
if (_isServer)
{
www = new WWW("http://192.168.88.100/ILRuntime/" +"HotFix_Project.dll");
}
else
{
www = new WWW("file://" + Application.streamingAssetsPath + "/HotFix_Project.dll");
}
//#endif
while (!www.isDone)
System.Threading.Thread.Sleep(100);
if (!string.IsNullOrEmpty(www.error))
Debug.LogError(www.error);
byte[] dll = www.bytes;
www.Dispose();
//#if UNITY_ANDROID
//www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.pdb");
//#else
if (_isServer)
{
www = new WWW("http://192.168.88.100/ILRuntime/" + "HotFix_Project.pdb");
}
else
{
www = new WWW("file://" + Application.streamingAssetsPath + "/HotFix_Project.pdb");
}
//#endif
while (!www.isDone)
System.Threading.Thread.Sleep(100);
if (!string.IsNullOrEmpty(www.error))
Debug.LogError(www.error);
byte[] pdb = www.bytes;
_fs = new MemoryStream(dll);
_p = new MemoryStream(pdb);
try
{
//IL中间汇编,加载到引擎中
Appdomain.LoadAssembly(_fs, _p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
}
catch
{
Debug.Log("加载热更新DLL失败,请确保已经生成DLL文件");
}
OnILRuntimeInitialized();
}
void OnILRuntimeInitialized()
{
Appdomain.Invoke("Hotfix.Game", "Initialize", null, null);
}
}
}
之后初始化之后可以调用测试的函数代码
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using Merge_County.Scripts.Tools;
namespace Merge_County.Scripts.ILRuntimeFramework
{
public class HotFixCall
{
private static HotFixCall _mInstance;
public static HotFixCall GetInstance()
{
if (_mInstance == null)
{
_mInstance = new HotFixCall();
}
return _mInstance;
}
/// <summary>
/// 调用没有返回值的静态方法 "HotFix_Project.HotFixHelloWorld" "HelloWorld"
/// </summary>
public void CallStaticMethod(string className,string methodName)
{
HotFixMgr.GetInstance().Appdomain.Invoke(className, methodName, null);
}
/// <summary>
/// 调用string返回值的静态方法
/// </summary>
/// <returns></returns>
public string CallStaticMethodWithString(string className,string methodName,string para)
{
// 获取类型
IType type = HotFixMgr.GetInstance().Appdomain.LoadedTypes[className];
// 获取方法
IMethod method = type.GetMethod(methodName, 1);
// 调用方法
object returnValue = HotFixMgr.GetInstance().Appdomain.Invoke(method, null, para);
Debugger.Log(returnValue);
// 输出返回值
return "0";
}
/// <summary>
/// 调用非静态方法
/// </summary>
/// <returns></returns>
public string CallMethodWithString(string className,string methodName)
{
// 获取类型
IType type = HotFixMgr.GetInstance().Appdomain.LoadedTypes[className];
// 创建实例
object instance = (type as ILType).Instantiate();
// 获取方法
IMethod method = type.GetMethod(methodName, 0);
// 调用方法
object returnValue = HotFixMgr.GetInstance().Appdomain.Invoke(method, instance);
Debugger.Log(returnValue);
// 输出返回值
return "0";
}
}
}
另外可以选择实现MonoBehavior的Adapter
以下是热更工程代码:
using UnityEngine;
namespace HotFix_Project.HotFixTest
{
//委托 MonoBehaviour 的方法
public class HotFixMonoBehaviour
{
void Awake()
{
Debug.Log("HotPro:Awake");
}
private void btnClick()
{
Debug.Log("HotPro:btnClick");
}
void Start()
{
Debug.Log("HotPro:Start");
}
void Update()
{
/*Debug.Log("HotPro:Update");*/
}
void OnDestroy()
{
Debug.Log("HotPro:OnDestroy");
}
}
}
之后在Unity工程内实现代码:
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.Runtime.Intepreter;
using UnityEngine;
namespace Merge_County.Scripts.ILRuntimeFramework
{
public class HotFixMonoBehaviourAdapter : MonoBehaviour
{
//挂载在游戏组件上,游戏组件会自动调用热更的mono方法
public string bindClass;
private IType classType;
private ILTypeInstance instance;
private IMethod update_method;
private IMethod start_method;
private IMethod ondestroy_method;
public virtual void Awake()
{
//创建需要创建的类型
classType = HotFixMgr.GetInstance().Appdomain.LoadedTypes[bindClass];
//创建实例
instance = (classType as ILType).Instantiate();
IMethod awake_method = classType.GetMethod("Awake", 0);
update_method = classType.GetMethod("Update", 0);
start_method = classType.GetMethod("Start", 0);
ondestroy_method = classType.GetMethod("OnDestory", 0);
if (awake_method != null)
{
HotFixMgr.GetInstance().Appdomain.Invoke(awake_method, instance);
}
}
private void Start()
{
if (start_method != null)
{
HotFixMgr.GetInstance().Appdomain.Invoke(start_method, instance);
}
}
// Update is called once per frame
void Update()
{
if (update_method != null)
{
HotFixMgr.GetInstance().Appdomain.Invoke(update_method, instance);
}
}
void OnDestroy()
{
if (ondestroy_method != null)
{
HotFixMgr.GetInstance().Appdomain.Invoke(ondestroy_method, instance);
}
}
}
}