UH4L7——委托调用
UH4L7——委托调用
本章代码关键字
1 | appDomain.DelegateManager.RegisterFunctionDelegate<>() //注册一种有参数的Action<>委托,以便于IL2CPP打包裁剪后还可以调用 |
委托调用
在委托的跨域调用中,如果出现Unity中自定义委托跨域关联ILRuntime中函数,需要进行:
- 注册委托(主要目的,避免IL2CPP打包裁剪报错)
- 注册委托转换器(主要目的,ILRuntime内部所有的委托都是以
Action
或Func
来存储的)
注意:
- 委托的注册相关流程必须在主工程中完成
- 为了避免添加自定义委托转换器
我们在使用委托时 尽量使用System
命名空间中的Action
和Func
,这样就不需要进行注册委托转换器了,只需要注册即可
在Unity中自定义委托后使用
-
ILRuntime中委托成员 关联ILRuntime工程中函数
直接常规使用即可,不会出现报错
在Unity主工程内声明如下委托
1
2public delegate void MyUnityDel1();
public delegate int MyUnityDel2(int i, int j);在ILRuntime热更新工程内可以直接使用相关内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class ILRuntimeMain
{
/// <summary>
/// 把逻辑处理权交给热更新工程,这是一个启动函数
/// </summary>
public static void Main()
{
MyUnityDel1 fun = Fun1;
fun();
MyUnityDel2 fun2 = Fun2;
int result = fun2(5, 6);
Debug.Log(result);
}
public static void Fun1()
{
Debug.Log("IL_Fun1");
}
public static int Fun2(int a, int b)
{
Debug.Log("IL_Fun2");
return a + b;
}
}输出:
-
Unity中委托成员 关联ILRuntime工程中函数
直接关联会出现报错,这里就涉及到委托成员的跨域
相当于Unity中的委托成员中存储了ILRuntime工程中的函数。就存在了跨域调用在Unity主工程的类内声明委托成员
1
2
3
4
5
6
7
8public delegate void MyUnityDel1();
public delegate int MyUnityDel2(int i, int j);
public class Lesson10 : MonoBehaviour
{
public MyUnityDel1 fun1;
public MyUnityDel2 fun2;
}ILRuntime热更工程内向Unity主工程内的类对象的委托成员添加热更工程内声明的方法并调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30using UnityEngine;
namespace HotFix_Project
{
public class ILRuntimeMain
{
public static void Main()
{
//在Unity中声明委托成员,关联ILRuntime工程中的函数
Lesson10 lesson10 = Camera.main.GetComponent<Lesson10>(); //对象挂载在了摄像机上
lesson10.fun1 = Fun1;
lesson10.fun1();
lesson10.fun2 = Fun2;
result = lesson10.fun2(7, 7);
Debug.Log(result);
}
public static void Fun1()
{
Debug.Log("IL_Fun1");
}
public static int Fun2(int a, int b)
{
Debug.Log("IL_Fun2");
return a + b;
}
}
}输出:
我们需要进行以下处理:可以通过报错信息中的提示,再进行初始化时进行代码的添加
主要有两部分:
-
注册委托(主要目的,避免IL2CPP打包裁剪报错)
对于无参无返回值的委托,由于
Action
本身就会被ILRuntime注册,因此不需要去注册假设要跨域调用
public delegate int MyUnityDel2(int i, int j)
这样的委托,
或者跨域使用Func<int, int, int>()
,就需要使用RegisterFunctionDelegate
注册一个对应的Func<int, int, int>()
假设要跨域调用有参无返回值的自定义委托,或者
Action<..>
委托,就需要使用RegisterMethodDelegate
注册一个对应的Action<..>
1
2appDomain.DelegateManager.RegisterMethodDelegate<int>(); //假设有一个无返回值的int参数的委托
appDomain.DelegateManager.RegisterFunctionDelegate<int, int, int>(); -
注册委托转换器(主要目的,ILRuntime内部所有的委托都是以
Action<>
或Func<>
来存储的)我们需要将委托转换为对应的
Action<>
或Func<>
,例如:假设要跨域调用
public delegate void MyUnityDel1()
这样的委托,就需要将其转换为Action
假设要跨域调用public delegate int MyUnityDel2(int i, int j)
这样的委托,就需要将其转换为Func<int, int, int>
其中,
Func<int, int, int>
我们需要先注册,这样我们才能确保在IL2CPP打包后也可以调用转换的格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//public delegate void MyUnityDel1()
appDomain.DelegateManager.RegisterDelegateConvertor<MyUnityDel1>((action) =>
{
return new MyUnityDel1(() =>
{
((System.Action)action)();
});
});
//public delegate int MyUnityDel2(int i, int j)
appDomain.DelegateManager.RegisterDelegateConvertor<MyUnityDel2>((func) =>
{
return new MyUnityDel2((i, j) =>
{
return ((System.Func<int, int, int>)func)(i, j);
});
});
在将dll和pdb文件以流的形式供appDomain
读取后,在初始化appDomain
时,根据报错信息依次添加如下代码
1 | //ILRuntime管理器内 |
输出:
注意:
- 委托的注册相关流程必须在主工程中完成,在ILRuntime热更工程内无效
- 为了避免添加自定义委托转换器,
我们在使用委托时,可以尽量使用System
命名空间中的Action<>
和Func<>
,这样就不需要进行注册委托转换器了,只需要注册即可
在ILRuntime中自定义委托后使用
-
ILRuntime中委托成员,关联ILRuntime工程中函数,直接使用即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public delegate void MyILRuntimeDel1();
public delegate int MyILRuntimeDel2(int i, int j);
public class ILRuntimeMain
{
public static void Main()
{
MyILRuntimeDel1 ilFun1 = Fun1;
ilFun1();
MyUnityDel2 ilFun2 = Fun2;
int ilResult = ilFun2(5, 6);
Debug.Log(ilResult);
}
public static void Fun1()
{
Debug.Log("IL_Fun1");
}
public static int Fun2(int a, int b)
{
Debug.Log("IL_Fun2");
return a + b;
}
} -
Unity中委托成员 关联ILRuntime工程中函数
一般不会出现基础工程中,使用还无法预知的可变代码,所以我们不需要考虑这种情况