Unity 中IOS平台 C#怎么和OC通信?
C#和Objective-C通信有多种方式,其中比较常见的方法是通过使用Mono框架中的Objective-C运行时库和C#的P/Invoke功能。
一、 C# 调用 OC的接口
1、首先介绍下 C#的P/Invoke功能
具体来说,我们可以通过在C#中使用DllImportAttribute特性和native方法签名来声明Objective-C中的函数。然后,我们可以在C#中调用这些native方法,从而实现与Objective-C的交互
首先在C# 中声明OC 中定义的接口,如下所示
public class SDKForIOS : MonoBehaviour
[DllImport("__Internal")]
private static extern void SDKInit(); // 此接口在mm文件中定义
public void Start()
SDKInit();
DllImport 其功能是提供从非托管DLL导出的函数的必要调用信息,DllImport属性应用于方法,要求最少要提供包含入口点的dll的名称。要不然调用不成功哦!!!
然后看OC中怎么定义的?
在头文件 SDKIOS.h 中定义
//用于Unity的调用(Unity只能调用C的方法,调不到OC的方法)
#if defined(__cplusplus)
extern "C"
#endif
extern void SDKInit();
#if defined(__cplusplus)
#endif
在源文件 SDKIOS.mm 中定义
void OnSDKInit()
NSLog(@"hello world!");
}
extern "C"会指示编译器这部分代码按C语言的方式进行编译,因为il2cpp后的代码都是按C语言的方式编译的,所以我们这里也要这样定义,要不调用会失败哦!!!
按照上面的方式我们启动游戏后就能看到打印"hello world!" 了。
2、使用Mono框架中的Objective-C运行时库来动态地获取Objective-C对象的方法和属性
当使用Mono框架中的Objective-C运行时库时,可以使用
objc_getClass
和
objc_msgSend
函数来获取Objective-C类和调用它们的方法。以下是一个简单的例子,演示如何使用这些函数从C#代码中访问Objective-C对象的方法和属性:
using System;
using System.Runtime.InteropServices;
public class Example
[DllImport("__Internal")]
private static extern IntPtr objc_getClass(string name);
[DllImport("__Internal")]
private static extern IntPtr objc_msgSend(IntPtr receiver, IntPtr selector);
[DllImport("__Internal")]
private static extern IntPtr objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);
static void Main()
// 获取NSString类
IntPtr nsstringClass = objc_getClass("NSString");
// 创建NSString对象
IntPtr nsstring = objc_msgSend(nsstringClass, Selector.GetHandle("stringWithUTF8String:"), "Hello, Objective-C!");
// 调用NSString对象的length方法
IntPtr lengthSelector = Selector.GetHandle("length");
int length = (int)objc_msgSend(nsstring, lengthSelector);
Console.WriteLine("Length of the string: {0}", length);
// 调用NSString对象的UTF8String属性
IntPtr utf8StringSelector = Selector.GetHandle("UTF8String");
IntPtr utf8String = objc_msgSend(nsstring, utf8StringSelector);
string str = Marshal.PtrToStringAuto(utf8String);
Console.WriteLine("UTF8 String: {0}", str);
// 定义Selector类,用于获取Objective-C方法的选择器
public static class Selector
[DllImport("__Internal")]
private static extern IntPtr sel_registerName(string name);
public static IntPtr GetHandle(string name)
return sel_registerName(name);
}
在上面的例子中,我们首先使用
objc_getClass
函数获取了Objective-C中的
NSString
类。然后使用
objc_msgSend
函数调用了
stringWithUTF8String:
方法,创建了一个
NSString
对象。接下来,使用
objc_msgSend
函数调用了
length
方法,获取了字符串的长度。最后,使用
objc_msgSend
函数调用了
UTF8String
属性,获取了字符串的UTF8编码。
需要注意的是,上面的例子只是演示了如何使用Objective-C运行时库来访问Objective-C对象的方法和属性,实际上还需要进行一些额外的操作才能将Objective-C对象和C#对象进行转换和交互。
二、OC怎么调用C#代码呢?
OC调用C#代码有 两种调用方式
第一种方式:
如果对Unity有些了解的同学肯定都知道一个接口,就是 UnitySendMessage ,然后传入组件的名字和方法的名字就可以调用了。
这种调用方式是线程安全的,但是可能会相对耗时一些,它的实现会遍历所有的transfrom然后找到相应的组件及方法进行调用。
第二种方式:
public class SDKIOS : MonoBehaviour
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void callbackN0Delegate(IntPtr data);
[DllImport("__Internal")]
public static extern void SetN0CallBack(IntPtr callback);
[DllImport("__Internal")]
private static extern void OnSDKInit();
// Start is called before the first frame update
void Start()
RegisterCallback();
OnSDKInit();
private void RegisterCallback()
callbackN0Delegate callbackN0_delegate = SendDataToGame;
//将Delegate转换为非托管的函数指针
IntPtr intptrN0_delegate = Marshal.GetFunctionPointerForDelegate(callbackN0_delegate);
//调用非托管函数
SetN0CallBack(intptrN0_delegate);
//原生层发送数据到游戏层
[MonoPInvokeCallback(typeof(callbackN0Delegate))]
static void SendDataToGame(IntPtr data)
var dataStr = Marshal.PtrToStringAnsi(data);
Debug.Log(dataStr);
如代码所示,一开始定义了委托函数 public delegate void callbackN0Delegate(IntPtr data); IntPtr类似于C++中的指针,用于和原生代码通信
[DllImport("__Internal")]
public static extern void SetN0CallBack(IntPtr callback);
这行代码代表原生层定义了SetN0CallBack 接口,用于回调SendDataToGame
RegisterCallback 函数目的是将委托函数SendDataToGame 通过SetN0CallBack 接口注册到原生层。
注意:[MonoPInvokeCallback(typeof(callbackN0Delegate))] 标签必须加,否则执行时会报错!!
接下来我们看下OC层是怎么定义的?
#if defined(__cplusplus)
extern "C"
#endif
extern void OnSDKInit();
typedef void(*CALLBACK_N0)(const char*); //定义函数指针
static CALLBACK_N0 callback_n0 = nil; //定义函数指针对象
void SetN0CallBack(CALLBACK_N0 callback);
#if defined(__cplusplus)
#endif
void OnSDKInit()
NSLog(@"OnSDKInit");
if(callback_n0 != nil)
callback_n0("call back ok!!!"); //这里将”call back ok!!!“字符串发给C#层打印