美文网首页
iOS原生集成unity—framework形式集成(二)

iOS原生集成unity—framework形式集成(二)

作者: 小蜗牛吱呀之悠悠 | 来源:发表于2020-08-20 18:30 被阅读0次

    以下所有内容均为个人观点,转载请注明出处<简书--小蜗牛吱呀之悠悠 >,谢谢!

    上篇文章我们讲到在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工程之间删除,新的考进去,然后用上一篇文章提到的方式,重新关联一遍。
    方式二:
    替换下面几个文件夹

    image.png
    接下来需要分情况了
    情况一:仅仅更新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工程,然后再将新建的类添加进去。

    相关文章

      网友评论

          本文标题:iOS原生集成unity—framework形式集成(二)

          本文链接:https://www.haomeiwen.com/subject/mmrejktx.html