【Unity3d】Unity与iOS之间通信
在Unity开发或者SDK开发经常遇到Unity与移动端原生层之间进行通信,这里把它们之间通信做一个整理。
关于Unity与Android之间通信,参考【Unity3d】Unity与Android之间通信
Unity调用Objective-C
主要分三个步骤:
(一)、在xcode中定义要被unity调用的函数
新建一个类,名字可以任意,比如UnityBridge:
头文件:UnityBridge.h (头文件中不需要字段和函数声明)
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface UnityBridge : NSObject@endNS_ASSUME_NONNULL_END
头文件里没什么代码,主要代码在实现文件中。
实现文件:UnityBridge.m
实现文件中需要用c语言定义函数,这些函数定义了之后,就可以被unity调用:
#import "UnityBridge.h"//如果c#调用oc函数时需要一个回调,需要先声明回调参数类型:
typedef void (*MyResultCallback) (int status,const char *result);//在.m文件中以下4行可以不需要
#if defined (__cplusplus)
extern "C"
{
#endif//这里写被unity调用的函数void test1(void){//这里是函数实现,支持oc语法}/*** int类型参数,返回int*/int test2(int params){//这里是函数实现,支持oc语法}/*** 字符串类型参数*/void test3(const char *params){//这里是函数实现,支持oc语法}/*** 返回字符串时,不能直接返回oc转c的字符串,要调用strdup函数再返回*/const char* test4(void){//返回字符串时,需要使用c分配内存再返回,否则闪退//return "abc" //错误,会闪退//return [@"abc" UTF8String];//错误,会闪退//return strdup("abc") //正确 //strdup函数需要引入#import return strdup([@"abc" UTF8String]) //要调用strdup()函数分配c内存再返回给unity,不然闪退}/*** 支持回调参数*/void test5(MyResultCallback callback){//这里是函数实现,支持oc语法int code = 0;NSString p = @"test";const char *result = [p UTF8String];//回调给c#callback(code,result)}//在.m文件中以下3行可以不需要
#if defined (__cplusplus)
}
#endif
函数返回类型是字符串时,oc这边不能直接返回oc转c的char*字符,否则闪退,c++闪退代码行:
…
// Marshaling cleanup of return value native representation
il2cpp_codegen_marshal_free(returnValue);
原因是oc使用了ARC自动释放内存,c层再去free内存发现未分配就会报错。
需要调用strdup()函数再返回,函数所在头文件:#import参见上面示例代码的test4()函数。
注意这些代码不要写在@implementation中,它是c语言的函数。
C++支持函数重载,而C不支持,两者的编译规则也不一样。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字可能为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不 同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。如果要在C++中使用C的函数,需要加extern "C"修饰。
#if defined (__cplusplus)这是一个宏判断,c++中才有这个宏。extern "C"也是c++的关键字。因为oc是支持c++(在.mm文件中才支持),extern "C"表示后面函数是c语言的,供外部调用的。如果在.m文件中,可以不需要extren “C”。
(二)、将oc代码复制到unity工程中。
将oc代码(包括.h和.m源文件)拷贝到Unity工程的Assets目录或子目录中。
实际上将oc代码放在unity工程的Assets目录下的任意位置都可以,oc代码会自动被unity引擎识别。
(笔者使用的unity版本是2019.4,以前的版本不知道是否可以是任意位置。)
为了方便管理,oc代码一般放在Assets/Plugins/iOS中。
也可以将代码打包成framework静态库,然后将其拷贝到unity工程的Assets目录中,一般放在 Assets/Plugins/iOS这个目录中。Unity导出xcode会自动依赖这个framework。
(三)、在unity的c#脚本中声明外部(oc)函数原型
using System.Runtime.InteropServices; //需要引入这个命名空间,会提示引入
using UnityEngine;public class Test{private Test() {}#if UNITY_IOS //加个宏比较好//以下是外部函数声明,函数签名必须与oc函数保持一致,参数类型用各自语言的,类型映射见文末。//声明无参数无返回值的函数[DllImport("__Internal")]private static extern void test1();//声明有一个int参数和int返回值的函数[DllImport("__Internal")]private static extern int test2(int p);//声明一个string参数的函数[DllImport("__Internal")]private static extern void test3(string p);//声明返回string类型的函数[DllImport("__Internal")]private static extern string test4();//如果需要oc的回调,声明一个回调函数类型delegate void MyResultDelegate(int code,string result);[DllImport("__Internal")]private static extern void test5(MyResultDelegate resultDelegate);/*** 回调函数的实现(或者叫实例)* 注意:必须是static类型的*/[AOT.MonoPInvokeCallback(typeof(MyResultDelegate))]private static void MyResultDelegateInstance(int code, string result){//这里写接收到oc回调的代码}#endifpublic void CallOC(){#if UNITY_IOStest1();int result1 = test2(1);test3("abc");string result2 = test4();test5(MyResultDelegateInstance);#endif}
}
在c#中调用oc中对应的方法,参见以上 CallOC()。
c#调用oc注意事项:
1、数据类型需要使用各自语言的,两者数据类型映射关系在文未。
2、c#中声明的oc方法、回调,都需要static修饰。
Objective-C调用Unity(c#)
oc调用c#比较简单,一般使用以下这个方法:
UnitySendMessage("MyTestObject", "TestFunc", "msg");
UnitySendMessage函数声明在UnityFramework.framework中UnityInterface.h头文件中:
void UnitySendMessage(const char* obj, const char* method, const char* msg);
第一个参数obj表示unity中物体GameObject的名字,注意不是c#脚本的名称也不是类名。
如下图:

第二个参数method表示这个物体挂载的c#脚本中方法的名字。
第三个参数表示msg表示这个方法接收的数据。
例如,以上物体MyTestObject挂载了MyScript.c#脚本(如上图),MyScript.c#中有TestFunc方法:
using UnityEngine;public class MyScript : MonoBehaviour
{private void TestFunc(string content){//这里是接收oc调用的实现} }
那么在oc中调用UnitySendMessage("MyTestObject", "TestFunc", "msg") c#的TestFunc方法就会执行。
如果有多个参数需要发送,推荐使用json格式。
oc调用c#注意事项:
1、需要依赖UnityFramework.framework框架。
2、unity工程导出的xcode工程默认已经有UnityFramework.framework。
3、如果是自己新建的xcode工程需要手动导入这个框架。
附:c#与oc数据类型映射:
| Unity(c#) | Objective-C |
|---|---|
| int | int |
| float | float |
| bool | bool |
| string | const char * |
| long | long long |
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
