美文网首页Unity与iOS
iOS与unity交互混编, 闭包方式实现互相调用

iOS与unity交互混编, 闭包方式实现互相调用

作者: yiangdea | 来源:发表于2019-01-15 15:55 被阅读61次

    背景

    unity需要调用其没有实现的原生功能。
    unity使用C#开发,可以与c++混编。
    iOS使用Objective-c开发,可以与C++和C混编。
    例如:

    • 支付,分享,音视频,但只提供了 iOS 平台 SDK。
    • 优秀插件
    • 需要通过 Objective-C 调用 iOS 原生类库代码。

    交互方式

    Unity 通过 C 与 iOS 进行交互。
    Unity 不能直接调用 C++ 的原因是 C++ 编译会有 Name mangling 问题。
    Objective-C 可以与 C/C++ 进行混编。使用 C 代码封装对应的 Objective-C 代码,提供给 Unity 使用。

    unity主动调用链:unity(C#) -> C -> iOS(Objective-C)
    iOS调用链: unity(C#) -> 注册回调到iOS -> iOS(Objective-C) -> 通过注册的回调,调用C -> 调用unity(C#)

    注意:建议 C 函数名加有特定意义的前缀,避免函数名冲突。

    unity交互部分

    核心文件上代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Runtime.InteropServices;  // 必须导入
    using System
    
    public class MonoPInvokeCallbackAttribute : Attribute   // 用于定义C语音回调的类
    {
        public MonoPInvokeCallbackAttribute(Type type)
        {
    
        }
    }
    
    public class BridgeUnityToNative   // 定义了一个类,用以做桥,可自定义
    {
        protected static BridgeUnityToNative _manager = null;
        public static BridgeUnityToNative Instance
        {
            get
            {
                if(_manager == null)
                {
                    _manager = new BridgeUnityToNative();
                }
                return _manager;
            }
        }
    
        public delegate void CallBack(int res);  // 定义回调,如果定义的方法需要有回调,则必须先定义delegate,才能核心交互代码中使用
        
        // 核心交互代码
        #if UNITY_IOS
        [DllImport("__Internal")]  // 固定形式,注册TestCallback方法为可调用的C函数
        private static extern void TestCallback();  // 封装必须为private, extern需要定义的方法,不然会报错
    
    
        [DllImport("__Internal")]
        private static extern void RegistCallback(CallBack callBack);  // 封装必须为private, extern需要定义的方法,不然会报错
    
        [AOT.MonoPInvokeCallback(typeof(CallBack))]  // 将LogCallback方法,注册为回调
        static void LogCallback(int res)
        {
            Debug.Log("调用了c# callback" + res);
        }
    
        public void TestCallbackFunc(int retCode)  // 对外接口方法,,外部文件调用此方法验证demo
        {
            Debug.Log("调用了TestCallbackFunc" + retCode);
            TestCallback();
            RegistCallback(BridgeUnityToNative.LogCallback);
        }
        #endif
    }
    

    上述代码,一共定义了两个交互函数。
    无回调方法TestCallback 和 有回调方法RegistCallback
    由于作用域的问题,两个方法都只能private。所以对外接口需要用c#包一层

    [AOT.MonoPInvokeCallback(typeof(CallBack))] 的下一个函数,可以用于回调代理。其函数类类型必须与代理完全一致,否则会报错
    这里函数名和回调类型,必须要跟iOS(Objective-C)的类型完全一致。不然会报错,无法调用整个函数。

    注意事项:TestCallback和'RegistCallback'方法。只在此处extern了方法名,所以不会有任何检查机制,C#或iOS改了方法,对方完全察觉不到,验证也很费劲。所以精心维护一份交互文档是很重要的。

    iOS交互部分

    因为要混C++ , 所有.m文件的后缀要改成.mm
    .h文件:

    //
    //  IOSToUnity.h
    //  Unity-iPhone
    //
    //  Created by yangda on 2019/1/12.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    #ifndef ConnectUnityToiOS_h
    #define ConnectUnityToiOS_h
    #endif /* ConnectUnityToiOS_h */
    
    @interface ConnectUnityToiOS : NSObject
    
    typedef void(*CallBack)(int retCode);
    
    + (ConnectUnityToiOS *)sharedInstance;
    
    extern "C"
    {
        void TestCallback();
        
        void RegistCallback(CallBack callBack);
    }
    
    @end
    

    其中:typedef void(*CallBack)(int retCode);对应C#代码中的代理public delegate void CallBack(int res);定义
    核心代码为:

    extern "C"
    {
        void TestCallback();
        
        void RegistCallback(CallBack callBack);
    }
    

    extern "C"可以扩展C函数,用于交互

    .m文件:

    //
    //  IOSToUnity.m
    //  Unity-iPhone
    //
    //  Created by yangda on 2019/1/12.
    //
    
    #import "ConnectUnityToiOS.h"
    
    @interface ConnectUnityToiOS()
    
    @property(atomic, assign)CallBack callBack;
    
    @end
    
    
    @implementation ConnectUnityToiOS
    // MARK:- OC部分
    static ConnectUnityToiOS *instance = nil;
    + (ConnectUnityToiOS *)sharedInstance{
        @synchronized(self) {
            if(instance == nil) {
                instance = [[[self class] alloc] init];
            }
        }
        return instance;
    }
    
    - (void)registTestCallBack:(CallBack)callBack {
        _callBack = callBack;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            _callBack(1);
            NSLog(@"iOS registTestCallBack");
        });
    }
    
    // MARK:- C++部分
    void TestCallback()
    {
        NSLog(@"TestCallback");
    }
    
    void RegistCallback(CallBack callBack)
    {
        NSLog(@"iOS RegistCallback");
        [ConnectUnityToiOS.sharedInstance registTestCallBack:callBack];
    }
    
    
    @end
    
    

    如果有错误的地方欢迎指正

    相关文章

      网友评论

        本文标题:iOS与unity交互混编, 闭包方式实现互相调用

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