Unity和iOS 原生专题二 Unity和iOS原生交互相互传值的两个方案

一 、方案一 通过指针传值和使用 MonoPInvokeCallback 从C#层向C层注册回调函数

1.1 iOS调用Unity函数Unity 给iOS传值

第一步C#端 定义 C#调用 ios 原生函数标识 固定写法

 /// <summary>
        /// 定义 C#调用 ios 原生函数标识 固定写法
        /// </summary>
        private const string DLLName = "__Internal";
        [UsedImplicitly, DllImport(DLLName)]
        private static extern void MobileNumberAuthiOS_Initialize(string secret, AliMobileAuthLogCallback logCallback,
            NumberAuthInitCallback initCallback);

第二步C#端 定义c# 传递到原生的的委托代理

 /// <summary>
        /// 定义c# 传递到原生的的委托代理,接收ios原生回传的值
        /// </summary>
        private delegate void AliMobileAuthLogCallback(string log);

        private delegate void NumberAuthInitCallback(int success, string msg);

第三步C# 端 定义C#端的代理函数,接收ios 传递过来的值

 /// <summary>
        /// 定义C#端的代理函数,用于接收ios 传递过来的值
        /// </summary>
        /// <param name="log"></param>
        [MonoPInvokeCallback(typeof(AliMobileAuthLogCallback))]
        private static void HandleOnAliMobileAuthLogCallback(string log)
        {
            InfoLog(log);
        }

        [MonoPInvokeCallback(typeof(NumberAuthInitCallback))]
        private static void HandleOnSmsAuthInitCallback(int success, string msg)
        {
            InfoLog($"开始初始化回调,success:{success} msg: {msg}");
            _initializeCallback?.Invoke(success, msg);
        }

第四步 C#端 调用上面定的调用ios 的函数

  /// C# 调用上面定的调用ios 的函数 ,secret 参数,HandleOnAliMobileAuthLogCallback,HandleOnSmsAuthInitCallback 要传递过去的代理函数
            MobileNumberAuthiOS_Initialize(secret, HandleOnAliMobileAuthLogCallback, HandleOnSmsAuthInitCallback);

第五步 ios 端 ios 定义c#调用的ios 方法  固定写法

///ios 定义c#调用的ios 方法  固定写法
#if defined(__cplusplus)
extern "C" {
#endif
    void MobileNumberAuthiOS_Initialize(const char* secret ,void(*aliMobileAuthLogCallback)(const char* log), void(*initSDKCallback)(int, const char * )){
        ///将c#的代理指针赋值给ios的块指针
        AliMobileAuthLogCallback = aliMobileAuthLogCallback;
        InitSDKCallback = initSDKCallback;
        ///调用ios的方法
        [[AliMobileNumberAuth sharedManager] Initialize:secret];
    }
    
#if defined(__cplusplus)
}
#endif

第六步ios 端  定义接收c#要传递过来的代理指针


///定义接收c#要传递过来的代理指针
static void (*AliMobileAuthLogCallback)(const char* log);
static void(*InitSDKCallback)(int,const char *);

第七步ios 端 在ios函数中 回调c#的代码函数,将ios这边的值传递到c#

-(void)Initialize:(const char*)key {
    ///接收c#传递过来的值
    NSString * dataString  = [NSString stringWithFormat:@"%s",key];
    ///ios 回调c#的代码函数,将ios这边的值传递到c#
    if (InitSDKCallback) {
        NSString * dataString = @"回传值";
        int code = 1;
      InitSDKCallback(code,[dataString UTF8String]);
      }
    
}

以上就是unity和ios 原生交互 通过指针传值和代理(delegate)回传值 定义和接收值的完整实现过程

第八步 C# 和ios 完整代码部分

8.1 ios 代码
//ios 代码
#import "AliMobileNumberAuth.h"


///定义接收c#要传递过来的代理指针
static void (*AliMobileAuthLogCallback)(const char* log);
static void(*InitSDKCallback)(int,const char *);


static bool EnableLog;
@interface  AliMobileNumberAuth()
@end

@implementation AliMobileNumberAuth

///ios 定义c#调用的ios 方法  固定写法
#if defined(__cplusplus)
extern "C" {
#endif
    void MobileNumberAuthiOS_Initialize(const char* secret ,void(*aliMobileAuthLogCallback)(const char* log), void(*initSDKCallback)(int, const char * )){
        ///将c#的代理指针赋值给ios的块指针
        AliMobileAuthLogCallback = aliMobileAuthLogCallback;
        InitSDKCallback = initSDKCallback;
        ///调用ios的方法
        [[AliMobileNumberAuth sharedManager] Initialize:secret];
    }
    
#if defined(__cplusplus)
}
#endif

-(void)Initialize:(const char*)key {
    ///接收c#传递过来的值
    NSString * dataString  = [NSString stringWithFormat:@"%s",key];
    ///ios 回调c#的代码函数,将ios这边的值传递到c#
    if (InitSDKCallback) {
        NSString * dataString = @"回传值";
        int code = 1;
      InitSDKCallback(code,[dataString UTF8String]);
      }
    
}
#pragma mark - LifeCycle
+(instancetype)sharedManager {
    static dispatch_once_t onceToken;
    static AliMobileNumberAuth *instance;
    dispatch_once(&onceToken, ^{
        instance = [[AliMobileNumberAuth alloc] init];
    });
    return instance;
}

-(void)MobileNumberAuthiOS_CheckEnvironment{
    
    [self LogMessage:@"开始检测当前环境是否支持一键登录"];
    __block BOOL support = YES;
    [[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSAuthTypeLoginToken complete:^(NSDictionary * _Nullable resultDic) {
        NSString *dataStirng = [[resultDic objectForKey:@"msg"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSString * code = [resultDic objectForKey:@"resultCode"];
        if (CheckEnvironmentCallback) {
            support = [PNSCodeSuccess isEqualToString:code];
            CheckEnvironmentCallback(support ? 1 : [code intValue],[dataStirng UTF8String]);
            CheckEnvironmentCallback = nil;
        }
        
        [self LogMessage:[NSString stringWithFormat:@"检测一键登录resultmsg:%@  resultCode:%@,是否支持一键登录:%d",[resultDic objectForKey:@"resultCode"],dataStirng,support]];
    }];
}
-(void)MobileNumberAuthiOS_GetToken{
    //3. 开始一键登录流程
    //3.1 调用加速授权页弹起接口,提前获取必要参数,为后面弹起授权页加速
UIViewController *rootViewController = [self topViewController];
    self.rootViewController = rootViewController;
__weak typeof(self) weakSelf = self;
TXCustomModel *model = [DoraemonModelCreate createAlert];
    
    [[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout:3.0 complete:^(NSDictionary * _Nonnull resultDic) {
        NSString *code = [resultDic objectForKey:@"resultCode"];
        NSString *dataStirng = [[resultDic objectForKey:@"msg"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        [self LogMessage:[NSString stringWithFormat:@"dataStirng%@",dataStirng]];
        if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
            if (NumberAuthGetTokenCallback) {
                NumberAuthGetTokenCallback([code UTF8String] ,[dataStirng UTF8String]);
                [rootViewController dismissViewControllerAnimated:YES completion:nil];
                NumberAuthGetTokenCallback = nil;
            }
            [self LogMessage:[NSString stringWithFormat:@"加速授权页弹起失败%@",dataStirng]];
            return ;
        }
        
        //3.2 调用获取登录Token接口,可以立马弹起授权页,model的创建需要放在主线程
        [[TXCommonHandler sharedInstance] getLoginTokenWithTimeout:1.0 controller:rootViewController model:model complete:^(NSDictionary * _Nonnull resultDic) {
            NSString *code = [resultDic objectForKey:@"resultCode"];
            NSString *dataStirng = [[resultDic objectForKey:@"msg"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            if ([PNSCodeLoginControllerPresentSuccess isEqualToString:code]) {
                [self LogMessage:@"弹起授权页成功"];
            } else if ([PNSCodeLoginControllerClickCancel isEqualToString:code]) {
                [self LogMessage:@"点击了授权页的返回"];
                if (NumberAuthGetTokenCallback) {
                    NumberAuthGetTokenCallback([code UTF8String] ,[dataStirng UTF8String]);
                    NumberAuthGetTokenCallback = nil;
                }
                [rootViewController dismissViewControllerAnimated:YES completion:nil];
            } else if ([PNSCodeLoginControllerClickChangeBtn isEqualToString:code]) {
                [self LogMessage:@"点击切换其他登录方式按钮"];

            } else if ([PNSCodeLoginControllerClickLoginBtn isEqualToString:code]) {
                if ([[resultDic objectForKey:@"isChecked"] boolValue] == YES) {
                    [self LogMessage:@"点击了登录按钮,check box选中,SDK内部接着会去获取登陆Token"];
                } else {
                    [[ToastUtil toast] showToast:@"请先同意协议"];
                    [self LogMessage:@"点击了登录按钮,check box未选中,SDK内部不会去获取登陆Token"];
                }
            } else if ([PNSCodeLoginControllerClickCheckBoxBtn isEqualToString:code]) {
                [self LogMessage:@"点击check box"];
            } else if ([PNSCodeLoginControllerClickProtocol isEqualToString:code]) {
                [self LogMessage:@"点击了协议富文本"];
            } else if ([PNSCodeSuccess isEqualToString:code]) {
                //点击登录按钮获取登录Token成功回调
                NSString *token = [resultDic objectForKey:@"token"];
                if (NumberAuthGetTokenCallback) {
                    NumberAuthGetTokenCallback([code UTF8String],[token UTF8String]);
                    [rootViewController dismissViewControllerAnimated:YES completion:nil];
                    NumberAuthGetTokenCallback = nil;
                }
                [[TXCommonHandler sharedInstance] hideLoginLoading];
                [self LogMessage:[NSString stringWithFormat:@"获取登录Token成功"]];
            } else{
                if (NumberAuthGetTokenCallback) {
                    NumberAuthGetTokenCallback([code UTF8String] ,[dataStirng UTF8String]);
                    NumberAuthGetTokenCallback = nil;
                }
                [[TXCommonHandler sharedInstance] hideLoginLoading];
                [self LogMessage:[NSString stringWithFormat:@"获取登录Token失败 "]];
            }
            [self LogMessage:[NSString stringWithFormat:@"授权框框操作日志msg:%@ code %@",dataStirng,code]];
        }];
    }];
    
}
-(void)MobileNumberAuthiOS_Dispose{
    
    [self.rootViewController dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - LifeCycle
+(instancetype)sharedManager {
    static dispatch_once_t onceToken;
    static AliMobileNumberAuth *instance;
    dispatch_once(&onceToken, ^{
        instance = [[AliMobileNumberAuth alloc] init];
    });
    return instance;
}
8.2 c# 代码

using System;
using System.Runtime.InteropServices;
using AOT;
using Bao.Debug;
using JetBrains.Annotations;

namespace Bao.Account.SDK
{
    public class MobileNumberAuthiOS 
    {
        #region 初始化🇭相关

        public static MobileNumberAuthiOS _instance;
        public static  Action<int, string> _initializeCallback;
       
        private Action<bool, string> _heckEnvironmentCallback;
        private Action<bool, string> _getTokenCallback;

        
        /// <summary>
        /// 定义c# 传递到原生的的委托代理,接收ios原生回传的值
        /// </summary>
        private delegate void AliMobileAuthLogCallback(string log);

        private delegate void NumberAuthInitCallback(int success, string msg);

        #endregion

        #region Native Methods
#if UNITY_IOS 
        /// <summary>
        /// 定义 C#调用 ios 原生函数标识 固定写法
        /// </summary>
        private const string DLLName = "__Internal";
        [UsedImplicitly, DllImport(DLLName)]
        private static extern void MobileNumberAuthiOS_Initialize(string secret, AliMobileAuthLogCallback logCallback,
            NumberAuthInitCallback initCallback);
#endif
        #endregion

        private static void InfoLog(string msg)
        {
            LogFile.get.Log($"阿里一键登录, iOS, {msg}");
        }
        
        public void Initialize(string secret, Action<int, string> callback, bool enableLog)
        {
            /// C# 调用上面定的调用ios 的函数 ,secret 参数,HandleOnAliMobileAuthLogCallback,HandleOnSmsAuthInitCallback 要传递过去的代理函数
            MobileNumberAuthiOS_Initialize(secret, HandleOnAliMobileAuthLogCallback, HandleOnSmsAuthInitCallback);
        }
        
        /// <summary>
        /// 定义C#端的代理函数,用于接收ios 传递过来的值
        /// </summary>
        /// <param name="log"></param>
        [MonoPInvokeCallback(typeof(AliMobileAuthLogCallback))]
        private static void HandleOnAliMobileAuthLogCallback(string log)
        {
            InfoLog(log);
        }

        [MonoPInvokeCallback(typeof(NumberAuthInitCallback))]
        private static void HandleOnSmsAuthInitCallback(int success, string msg)
        {
            InfoLog($"开始初始化回调,success:{success} msg: {msg}");
            _initializeCallback?.Invoke(success, msg);
        }

    }
}

private delegate void OnViewClosed(int result, string msg);   // 

[MonoPInvokeCallback(OnViewClosed)]
static void CalledByNativeC(int result, string msg)
{
    // some logic here
}

// ... 

#if UNITY_IPHONE || UNITY_IOS
[DllImport("__Internal")]
private static extern void SetOnViewClosed(OnViewClosed);
#endif

// ...
SetOnViewClosed(CalledByNativeC);    // 把C#中的回调函数传给C

二 、方案二 UnitySendMessage

2.1 使用 UnitySendMessage 时具有以下限制:

1.通过原生代码,只能调用与以下签名对应的脚本方法:void MethodName(string message);。

2.对 UnitySendMessage 的调用是异步的,并有一帧延迟

3.如果两个或多个游戏对象具有相同的名称,则在使用 UnitySendMessage 时可能导致冲突

4.无论使用什么方式调用UnitySendMessage方法,方法最终会使用主线程运行。

2.2 UnitySendMessage 使用方法

UnitySendMessage("[gameobject_name]", "[method_name]", "[string_param]");
这个方法要求场景中有个特定名称的GameObject对象,同时该对象上应该挂载某个MonoBehaviour脚本,在该脚本中包含有一个特定的方法(如下所示),当然如果该对象上挂载了多个脚本,并且这些脚本中都有该方法,那么这些方法都会被调用的!

2.3 iOS 向C# 发送消息

 MessageReceiver (MessageReceiver脚本绑定到MessageReceiver该游戏对象上)

UnitySendMessage("MessageReceiver", "OnMessageReceived", "Hello from iOS!");
using UnityEngine;

public class MessageReceiver : MonoBehaviour
{
    public void OnMessageReceived(string message)
    {
        Debug.Log("Received message from iOS: " + message);
    }
}

2.4 Unity调用iOS原生方法

using UnityEngine;
using System.Runtime.InteropServices;

public class NativeMethodCaller : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void CallNativeMethod(string message);

    public void CalliOSMethod(string message)
    {
        CallNativeMethod(message);
    }
}

2.5 ios 实现方法

extern "C" {
    int CallNativeMethod(const char *msg) {
        
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/576828.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的口腔管理平台设计与实现

基于Spring Boot的口腔管理平台设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 管理员登录界面图&#xff0c;管理员登录进入口腔管理平…

Spring Cloud OpenFeign使用

OpenFeign源于Netflix的Feign&#xff0c;是http通信的客户端。屏蔽了网络通信的细节&#xff0c;直接面向接口的方式开发&#xff0c;让开发者感知不到网络通信细节。 所有远程调用&#xff0c;都像调用本地方法一样完成。 Spring Cloud OpenFeign 是 Spring Cloud 对 Feign …

Unity AssetsBundle打包

为什么要使用AssetsBundle包 减少安装包的大小 默认情况下&#xff0c;unity编译打包是对项目下的Assets文件夹全部内容进行压缩打包 那么按照这个原理&#xff0c;你的Assets文件夹的大小将会影响到你最终打包出的安装包的大小&#xff0c;假如你现在正在制作一个游戏项目&…

Aigtek:功率信号源是什么东西

功率信号源是一种电子设备&#xff0c;它可以提供可控的、稳定的高功率输出信号。通常用于测试和校准功率放大器、天线等设备&#xff0c;以及进行无线通信、雷达和卫星导航等应用中。下面将详细介绍功率信号源的概念、功能和特点。 功率信号源的概念 功率信号源是指能够产生可…

SCSS的基本使用(一)

目录 一、使用&符号来引用父选择器 二、scss的语法 三、变量&#xff08;Variables&#xff09; 四、嵌套&#xff08;Nesting&#xff09; 五、mixin 和 include 六、extend 继承 七、import 与 Partials 八、if简单判断 九、if复杂判断 一、使用&符号来引用父…

鸿蒙云函数调试坑点

如果你要本地调试请使用 const {payload, action} event.body/** 本地调试不需要序列化远程需要序列化 */ // const {payload, action} JSON.parse(event.body) const {payload, action} event.body 注意: 只要修改云函数&#xff0c;必须上传云函数 如果使用 const {pay…

【服务器部署篇】Jenkins配置后端工程自动化部署

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0c;产…

【亲测对比】大厂云服务器2-64G对比表 不卡顿 幻兽帕鲁 我的世界 雾锁王国 饥荒联机版 英灵神殿通用

更新日期&#xff1a;4月26日&#xff08;京东云采购季持续进行&#xff09; 本文纯原创&#xff0c;侵权必究 《最新对比表》已更新在文章头部—腾讯云文档&#xff0c;文章具有时效性&#xff0c;请以腾讯文档为准&#xff01; 【腾讯文档实时更新】2024年-幻兽帕鲁服务器专…

C语言系列文章 | 初识C语言

首先分为几个方面来和各位读者介绍C语言&#xff0c;并在之后的学习过程中不断地和各位读者去分享我学习的经历。 坐好&#xff0c;发车咯~目录如下&#xff1a;1. C语言是什么&#xff1f;2. C语言的历史和辉煌3. 编译器的选择VS20224. VS项目和源⽂件、头⽂件介绍5. 第⼀…

关于java对接微信公众号(对接百度AI实现图片文字识别,对接聚合数据实现笑话、谜语大全,成语接龙等功能)

前言&#xff1a; 只是自己学习使用&#xff0c;所以有点不规范&#xff0c;请见谅 本文直接附上源码与效果图&#xff0c;具体操作步骤请参考另一篇文章&#xff1a;http://t.csdnimg.cn/PQu25 1.运行效果图 1.1 关注事件 1.2 笑话大全 1.3 谜语大全 1.3 多级菜单 1.4 按钮…

MySQL基础知识——MySQL索引

深入浅出索引 索引的意义 索引的意义&#xff1a;在大量数据中&#xff0c;加速访问少量特定数据&#xff1b; 使用索引的前提条件&#xff1a; 1&#xff09;索引块数量小于数据块数量&#xff1b; 2&#xff09;索引键有序&#xff0c;故可以使用二分查找等高效的查找方式&…

互联网安全面临的全新挑战

前言 当前移动互联网安全形势严峻&#xff0c;移动智能终端漏洞居高不下、修复缓慢&#xff0c;移动互联网恶意程序持续增长&#xff0c;同时影响个人和企业安全。与此同时&#xff0c;根据政策形势移动互联网安全监管重心从事前向事中事后转移&#xff0c;需加强网络安全态势感…

ETF期权是什么详解

ETF期权是什么 ETF期权的本质是一种金融衍生品&#xff0c;与交易所交易基金&#xff08;Exchange-Traded Fund&#xff0c;简称ETF&#xff09;相关的期权合约。其核心在于赋予了投资者在未来某个时间点以约定价格买入或卖出特定ETF&#xff08;交易所交易基金&#xff09;的…

百望云发布金盾企业经营大模型,暨光明食品、法雷奥、西奥电梯财税数字化实践分享

百望云发布金盾企业经营大模型&#xff0c;暨光明食品、法雷奥、西奥电梯财税数字化实践分享 数字化转型思想指导下&#xff0c;如何标定好、利用好、管理好数据资产&#xff0c;已经成为企业寻找发展新动能的着力点。 基于此&#xff0c;“2024数字商业创新论坛”于4月26号在上…

2017美亚杯--个人赛

1、Gary的笔记本电脑已成功取证并制作成镜像 (Forensic Image)&#xff0c;下列哪个是其MD5哈希值。A.0CFB3A0BB016165F1BDEB87EE9F710C9 B.5F1BDEB87EE9F710C90CFB3A0BB01616 C.A0BB016160CFB3A0BB0161661670CFB3 D.16160CFB3A0BB016166A0BB016166167 E.FB3A0BB016165 B016166…

【论文阅读】Self-DC:何时检索,何时生成?

对于RAG来说&#xff0c;什么时候利用外部检索&#xff0c;什么时候使用大模型产生已知的知识&#xff0c;以回答当前的问题?这是一个非常有趣的话题。 《Self-DC: When to retrieve and When to generate? Self Divide-and-Conquer for Compositional Unknown Questions》这…

环境配置——Windows平台配置VScode运行环境为远程服务器或虚拟机

1. 远程机需要先安装SSH服务&#xff0c;命令如下 sudo apt install openssh-server 2. 安装好后需要开启SSH服务&#xff1a; sudo service sshd start 3. 查看SSH服务是否有被开启&#xff1a; sudo systemctl status sshd.service 4. 本地Windows需要生成密钥将公钥放…

Windows 安全中心:页面不可用 你的 IT 管理员已限制对此应用的某些区域的访问,并且你尝试访问的项目不可用。有关详细信息,请与 IT 支持人员联系。

问题 1&#xff1a;Windows 安全中心提示&#xff1a;【页面不可用 你的 IT 管理员已限制对此应用的某些区域的访问&#xff0c;并且你尝试访问的项目不可用。有关详细信息&#xff0c;请与 IT 支持人员联系。】 修复 Microsoft.SecHealthUI 方法 1&#xff1a;命令自动重装安…

IDM下载器_Internet Download Manager 6.42.7

网盘下载 IDM下载器是一款针对互联网所打造的下载管理器。IDM下载器能将下载速度提高5倍&#xff0c;恢复因丢失的连接&#xff0c;网络问题&#xff0c;计算机关闭或意外断电而重新启动中断或中断的下载。IDM下载器还可支持所有流行的浏览器&#xff0c;以使用独特的“高级浏…

mysql8.0免安装版windows

1.下载 MySQL下载链接 2.解压与新建my.ini文件 解压的路径最好不要有中文路径在\mysql-8.0.36-winx64文件夹下新建my.ini文件&#xff0c;不建data文件夹(会自动生成) [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录(尽量用双斜杠\\,单斜杠\可能会报错) basedirD:\…
最新文章