Unity IL2CPP桥接iOS

6 阅读2分钟

🎯目标

由于iOS目前不支持JIT模式的Mono引擎,项目中将mono替换为了IL2CPP,这样一来,原来的桥接方式就无法使用了,只能调研一种新的桥接方式。

☕️实现

IL2CPP在构建时会将C#代码转化成C++代码,这样的话,如果想在C#中像以前一样使用Action作为回调传入OC中,就需要将C#中的Action存储到一个全局字典中,然后通过id区分,之后定义一个静态方法用于创建函数指针和id一起传给C++层,之后C++层中调用OC接口并在:接口Block中调用传入的函数指针返回id。

  1. Unity C# Action
  2. 通过全局字典存储,并定义统一处理的静态函数
  3. 将IntPtr传递给C++接口
  4. 在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;
}