unityloverz 发表于 2022-3-26 20:54

Unity 与 iOS 使用委托通信


Unity摊

从原生代码回调 C
Unity iOS 支持有限的原生到托管回调功能。有两种方式可以做到这一点:
使用 UnitySendMessage

通过委托

使用 UnitySendMessage


此选项更简单,但有一些限制。如下所示:
UnitySendMessage("GameObjectName1", "MethodName1", "Message to send");有三个参数:目标 GameObject 的名称用于调用该对象的脚本方法用于传递给被调用方法的消息字符串
使用 UnitySendMessage 时具有以下限制:
通过原生代码,只能调用与以下签名对应的脚本方法:void MethodName(string message);。对 UnitySendMessage 的调用是异步的,并有一帧延迟。If two or more GameObjects have the same name, this can cause conflicts when you use UnitySendMessage.
使用委托


当使用委托时,C# 端的方法必须是静态的,并且必须用 MonoPInvokeCallback 属性进行标记。必须将该方法作为委托传递给在原生代码中作为函数实现的 extern 方法,这个函数采用一个指针,而指针则指向具有对应签名的函数。然后,原生代码中的函数指针再引回 C# 静态方法。
以上信息来源于 Untiy官方


-----------------------------这是一条分割线-----------------------------

实现目的: 支付或者原生SDK回调(等) 返回时 需要通知Unity侧做出响应, 这里我们就需要先从Unity(注册)传递一堆函数指针(委托)到OC, OC端将它们保存到内存中, 在合适的时机进行调用, 从而回传到Unity;

为了更方便的使用, 我们将其封装成静态库;

静态库结构

具体实现:
1. Xcode->New Project->Static Library -> Project Name User-defined


image.png

UnityMessageCenter.h
////UnityMessageCenter.h//UnityMessageCenter////Created by jens on 2022/3/16.//#import <Foundation/Foundation.h>#if defined (__cplusplus)extern "C"{#endiftypedef void (*MessageResultHandler) (int arg1, int arg2, const char * content);#if defined (__cplusplus)}#endif@interface UnityMessageCenter : NSObject@property(nonatomic, retain) NSMutableDictionary *mMessageDic;+(UnityMessageCenter*)shareInstance;-(BOOL)sendMessageToUnityWithMessageId:(NSString *)messageId arg1:(int)arg1 arg2:(int)arg2 content:(NSString *)content;@end
UnityMessageCenter.m
////UnityMessageCenter.m//UnityMessageCenter////Created by jens on 2022/3/16.//#import "UnityMessageCenter.h"@implementation UnityMessageCentertypedef void (^MessageResultHandlerTemp) (int arg1, int arg2, const char * content);@synthesize mMessageDic;+(NSString*) CreateString:(const char* )str{    if (str){      return ;    }    return ;}+(UnityMessageCenter*)shareInstance{    static dispatch_once_t onceToken;    static UnityMessageCenter* instance = nil;    dispatch_once(&onceToken, ^{      instance = [init];      instance.mMessageDic =;    });    return instance;}-(BOOL)sendMessageToUnityWithMessageId:(NSString *)messageId arg1:(int)arg1 arg2:(int)arg2 content:(NSString *)content{    MessageResultHandlerTemp handler = ;    if (content ==nil) {      content= @"";    }    if(handler!=nil){      handler(arg1,arg2, content.UTF8String);      return YES;    }    return NO;}@end#if defined (__cplusplus)extern "C"{#endif    void RegisterDelegateToIOS (const char * messageId,MessageResultHandler resultHandler){      UnityMessageCenter *msg = ;      NSString *msgId = ;      MessageResultHandlerTemp temp =^void(int a,int b,const char *c){            return resultHandler(a,b,c);      };      ;    }    #if defined (__cplusplus)}#endif
C#.CS脚本代码
            public delegate void MessageResultHandler(int arg1, int arg2, string messageContent);      #if UNITY_IOS            static extern void RegisterDelegateToIOS (string messageId, IntPtr resultHandler);#endif      public void RegisterMessageHandler(string messageId, MessageResultHandler callback)      {#if UNITY_IOS            IntPtr fp = Marshal.GetFunctionPointerForDelegate(callback);            RegisterDelegateToIOS(messageId,fp);#endif      }
: 表面这个委托不受C#管理, 即非托管内存, 详细参考: 托管和非托管。
CallConvention(调用约定):决定函数参数传送时入栈和出栈的顺序,Cdecl表示由调用方把参数出栈。

: 表示函数位于__Internal.Dll中, 固定写法。

: 标记方法是由C或者C++来调用的。

Marshal.GetFunctionPointerForDelegate() : 获取函数指针。

需要注意的是:
1. C中一定要有block与C#中的代理对应;
2. OC字典只能存储非nil对象;
typedef void (*MessageResultHandler) (int arg1, int arg2, const char * content);public delegate void MessageResultHandler(int arg1, int arg2, string messageContent);
最后编译Xcode生成libUnityMessageCenter.a 和 UnityMessageCenter.h头文件, 拿到其它OC代码即可使用;

具体使用参考示例:
#import "UnityMessageCenter.h" [ sendMessageToUnityWithMessageId:OnInitialized arg1:0 arg2:0 content:@""];
参考博客(感谢):

https://www.jianshu.com/p/f01c7e3f666c

https://docs.unity3d.com/cn/2020.3/Manual/PluginsForIOS.html

https://zhuanlan.zhihu.com/p/137970936
页: [1]
查看完整版本: Unity 与 iOS 使用委托通信