🎯目标
由于iOS目前不支持JIT模式的Mono引擎,项目中将mono替换为了IL2CPP,这样一来,原来的桥接方式就无法使用了,只能调研一种新的桥接方式。
☕️实现
IL2CPP在构建时会将C#代码转化成C++代码,这样的话,如果想在C#中像以前一样使用Action作为回调传入OC中,就需要将C#中的Action存储到一个全局字典中,然后通过id区分,之后定义一个静态方法用于创建函数指针和id一起传给C++层,之后C++层中调用OC接口并在:接口Block中调用传入的函数指针返回id。
- Unity C# Action
- 通过全局字典存储,并定义统一处理的静态函数
- 将IntPtr传递给C++接口
- 在C++中在调用OC方法,并传入一个调用了静态函数的Block
这个过程与cocos JSB 的桥接逻辑相似。
0. 定义OC接口
OC接口通过Framework引入,这里不做修改
typedef void (^CompletionBlock)(int resultCode, NSString *msg, NSString *result);
- (void)run:(CompletionBlock)block {
if (block) {
block(200, @"success", @"data");
}
}
1. Unity 接口
C#接口定义如下:
public static void Run(Action<int, string, string> callback)
{
// TODO 后续处理
}
这里定义了一个Action<int, string, string> callback 作为桥接的起点。
2. 静态处理方法定义
这一步需要定义一个静态方法,并根据id调用提前保存好的Action.
首先定义一个与OC端Block格式对齐的delegate。
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeCallback(int callbackId, int code, string msg, string result);
之后,定义一个供OC调用的,用来统一处理OC返回值的静态方法
[MonoPInvokeCallback(typeof(NativeCallback))]
public static void OnNativeCallback(int callbackId, int code, string msg, string result)
{
// 根据callbackId调用对应的Block
if (_callbacks.TryGetValue(callbackId, out var cb))
{
cb?.Invoke(code, msg, result);
}
}
3. 补充Unity调用方法
回到之前定义的 Run(Action<int, string, string> callback)方法。这一步的目的就是将OnNativeCallback和callbackId代替Action传递给OC。
首先定义OC方法
[DllImport("__Internal")]
private static extern void OC_Run(int callbackId, IntPtr callback);
之后生成参数并调用
NativeCallback callback = OnNativeCallback;
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(callback);
int callbackId = registerAction(callback); // TODO 后续实现,很简单
OC_Run(callbackId, ptr);
4. 桥接文件
typedef void (*UnityCallback)(int resultCode, const char* msg, const char* result);
void RunWithUnityCallback(int callbackId, void* callbackPtr) {
UnityCallback callback = (UnityCallback)callbackPtr;
CompletionBlock block = ^(int resultCode, NSString *msg, NSString *result) {
if (callback) {
callback(callbackId, resultCode, [msg UTF8String], [result UTF8String]);
}
};
[[MySDK sharedInstance] run:block];
}
5. Action 管理
接下来是实现对Action的存储和管理
private static readonly Dictionary<int, Action<int, string, string>> _callbacks = new();
private static int _callbackCounter = 1; // 0保留不用
private static CompletionDelegate _delegate;
static NativeBridge()
{
_delegate = OnNativeCallback;
}
private static void registerAction(Action<int, string, string> callback){
int callbackId = _callbackCounter++;
_callbacks[callbackId] = callback;
return callbackId;
}