以下所有内容均为个人观点,转载请注明出处<简书--小蜗牛吱呀之悠悠 >,谢谢!
上篇文章我们讲到在unity版本更新后,如何以最快最简单的方式将unity导出的工程集成到iOS原生工程,并构建关联、iOS原生处代码配置、启动unity。本文将延续上一篇文章,将继续讲述在集成成功以后,iOS与unity之间如何互相通信与交互,并总结出unity版本需要更新时iOS原生需要做的事情。
一、背景
unity版本更新后,unity工程和iOS原生工程是以同层级的形式存在于一个workspace下,因此,两个工程之间文件的根路径就不一样了,访问也没有这么方便。因此,本文将讲述两种非常通俗易懂的unity调用原生方法的方式。
方式一:通知交互
方式二:桥接交互
二、通知交互
顾名思义,通知交互就是在unity需要调用原生的方法时,从unity向原生发送一条通知,并将参数携带过去。
//将在Unity中引用的C代码�
extern void ShowWarningBox(char *strText) {
//创建UIAlertController
[[NSNotificationCenter defaultCenter] postNotificationName:@"test" object:nil userInfo:@{@"test":@"这是一个测试数据"}];
};
在unity工程,新建一个交互类,在类中定义实现各种功能的函数(C语言语法),函数体中发送通知,可以将方法名作为通知名称传递,参数则通过userInfo字典传递,然后在接收的时候再做相应的处理。
注意:当你新建完交互类或者往交互类中新增过方法之后,需要将unity工程重新导出一份,然后再以下文提到的版本更新方式重新导入。
三、桥接交互
在上一篇文章中的集成步骤中有提到一个桥接文件NativeCallProxy.h,这个文件是做什么用的呢?由于unity的实现是C#语言,无法直接调用OC的方法,所以需要通过桥接的形式将C#的事件传递给原生。
首先,我们看一下NativeCallProxy.h的内容
#import <Foundation/Foundation.h>
// NativeCallsProtocol defines protocol with methods you want to be called from managed
@protocol NativeCallsProtocol
@required
- (void) showHostMainWindow:(NSString*)color;
- (void)testUnity:(NSString*)test;
// other methods
@end
__attribute__ ((visibility("default")))
@interface FrameworkLibAPI : NSObject
// call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi;
@end
文件中的registerAPIforNativeCalls方法就是上一篇文章中集成时候添加的代码:
[NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
另一部分则是协议方法,整个结构与类构建代理的过程非常相似,但有一处需要注意:registerAPIforNativeCalls方法设置代理并没有使用weak
接下来我们再看.m文件的内容:
id<NativeCallsProtocol> api = NULL;
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
{
api = aApi;
}
@end
extern "C" {
void showHostMainWindow(const char* color) {
return [api showHostMainWindow:[NSString stringWithUTF8String:color]];
}
void testUnity(const char *test) {
return [api testUnity:[NSString stringWithUTF8String:test]];
}
}
其中extern "C" 中的函数就是桥接函数,在此处定义并实现函数后,unity也需要声明这些函数。,当unity调用这些函数的时候,就会在这里完成函数-方法的转换,在OC原生代码中,实现对应的协议方法,就可以完成完整的交互了。
注意:extern "C"中添加函数后,需要unity也声明相关函数并导出工程
四、OC调用unity的函数
oc调用unity函数的方式就更简单了,直接用下面的函数就可以了
- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg
参数一:直接问unity的同学拿就可以了
参数二:函数名
参数三:传参,只能字符串传递,多个参数的情况下,与unity的同学约定好字符串的切割格式。
事例:
[[self ufw] sendMessageToGOWithName: "AvatarSys" functionName: "ChangeModel" message: "hair-4"];
注意:这个方法需要在unity初始化完成以后才能调用
五、unity工程更新
当我们拿到新的unity工程以后,有两种方式更新
方式一:将旧的unity工程之间删除,新的考进去,然后用上一篇文章提到的方式,重新关联一遍。
方式二:
替换下面几个文件夹
接下来需要分情况了
情况一:仅仅更新unity的内容,不涉及交互,那么在替换完文件夹之后,需要检查一下Data文件夹和桥接文件的配置
image.png
image.png
如果上述内容都OK,直接运行就可以了,如果上述内容需要修改,在修改后还需要对framework重新build一下
情况二:桥接文件有修改,在替换完文件夹后,除了情况一提到的内容外,还需要检查一下你原生的UnityFramework.framework下的桥接文件中,修改的内容是否存在,如果不存在,在build完UnityFramework.framework以后,需要进入到iOS原生工程的target下,重新导入一次UnityFramework.framework,导入方式请参考上一篇文章所述。
image.png
六、遇到的一些问题
1、不管是桥接文件,还是自定义的类,经过unity导出后,新增#import导入头文件、修改函数名都需要重新导出unity工程,否则framework编译不过,会报对应的方法找不到的错误,如下图。但是修改函数体,可以不需要重新导出。
image.png
2、unity工程下如果新建一个类,需要在unity中引用,需要重新导出unity工程。可以将新建的类放入unity中一起导出,也可以只在需要导入头文件的地方写好#import以后直接先导出unity工程,然后再将新建的类添加进去。
网友评论