Unity3D与iOS的交互 简单版开箱即用

本文适合的情况如下:

Unity客户端人员 与 IOS端研发人员合作的情况

目录

From U3D to iOS

实现原理

1.unity工程目录创建2个文件 NativeCallProxy.m、NativeCallProxy.h 并且放到Unity工程目录Plugins/iOS/unity_ios_plus目录下

2.创建C#调用脚本 定义对应.mm脚本的 调用接口,调用也如下


From U3D to iOS

实现原理

由于U3D无法直接调用Objc或者Swift语言声明的接口,幸好U3D的主要语言是C#,因此可以利用C#的特性来访问C语言所定义的接口,然后再通过C接口再调用ObjC的代码(对于Swift代码则还需要使用OC桥接)。

下面演示:利用C#的特性来访问C语言所定义的接口,然后再通过C接口再调用ObjC的代码

1.unity工程目录创建2个文件 NativeCallProxy.m、NativeCallProxy.h 并且放到Unity工程目录Plugins/iOS/unity_ios_plus目录下

 NativeCallProxy.m代码内容:

#import <Foundation/Foundation.h>
#import "NativeCallProxy.h"//固定写法
@implementation FrameworkLibAPIid<NativeCallsProtocol> api = NULL;
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
{api = aApi;
}
//固定写法结束
@end//固定写法
extern "C" {
//void showHostMainWindow(const char* color) { return [api showHostMainWindow:[NSString stringWithUTF8String:color]]; };//返回字符串的1个函数
const char*  unityCallGetInitData(){NSString* str=[api unityCallGetInitData];char* ret = nullptr;
//    ret = (char*)malloc([str length]+1);
//    memcpy(ret, [str UTF8String], ([str length])+1);ret = (char*)malloc([str length]);memcpy(ret, [str UTF8String], [str length]);return ret;    
};//无返回的1个函数
void unityCallJumpLogin(){return  [api unityCallJumpLogin];
};//无返回、传入字符串的函数
void unityCallJumpToRecharge(const char* gameStatus,const char* receOBName,const char* methodName){return [api unityCallJumpToRecharge:[NSString stringWithUTF8String:gameStatus] :[NSString stringWithUTF8String:receOBName] :[NSString stringWithUTF8String:methodName]];};void unityCallCloseVC(){return [api unityCallCloseVC];
};//隱私按鈕
void onPrivacyButton(){return [api onPrivacyButton];
}//儲值按鈕
const char* storedValue(){NSString* str=[api storedValue];char* ret = nullptr; ret = (char*)malloc([str length]);memcpy(ret, [str UTF8String], [str length]);return ret;
}//切换游戏
const char* ChangeGame(){NSString* str=[api ChangeGame];char* ret = nullptr;ret = (char*)malloc([str length]);memcpy(ret, [str UTF8String], [str length]);return ret;}}//extern "C" {
//
//}

NativeCallProxy.h代码内容

// [!] important set UnityFramework in Target Membership for this file
// [!]           and set Public header visibility//固定写法
#import <Foundation/Foundation.h>
// NativeCallsProtocol defines protocol with methods you want to be called from managed
@protocol NativeCallsProtocol
@required// other methods 自定义方法
/**获取初始json数据:baseUrl、mac_id、gameType、jwt 【对应mm文件的自定义函数名】*/
-(NSString*)unityCallGetInitData;
/**重新登录	【对应mm文件的自定义函数名的接口】*/
-(void)unityCallJumpLogin;
/**跳充值页前保存数据,充值页返回后把保存的数据发信息给unity 【对应mm文件的自定义函数名的接口】*/
-(void)unityCallJumpToRecharge:(NSString*) gameStatus :(NSString*) receOBName :(NSString*) methodName;//ios——关闭vc 【对应mm文件的自定义函数名的接口】
-(void)unityCallCloseVC;//隱私按鈕 【对应mm文件的自定义函数名的接口】
-(void)onPrivacyButton;//储值按钮 【对应mm文件的自定义函数名的接口】
-(NSString*)storedValue;//ch Game 【对应mm文件的自定义函数名的接口】
-(NSString*)ChangeGame;//自定义方法结束
@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

勾选iOS平台

2.创建C#调用脚本 定义对应.mm脚本的 调用接口,调用也如下

using System;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using UnityEngine.SceneManagement; //引入  这个命名空间,让unity可以使用 Assets/Plugins/iOS 或 Android/ 这里的dll文件/// <summary>
/// 呼叫安卓或 IOS 工具类
/// </summary>
public class CallAndroidOrIos :MonoBehaviour
{public static CallAndroidOrIos instance;private void Awake(){instance = this;}#region  关于IOS的操作/// <summary>/// 模拟 安卓或iOS ,DLL的类;/// </summary>public class NativeAPI{#if UNITY_EDITOR || UNITY_ANDROID/// <summary>/// 获取 IOS返回的 json数据 :baseUrl、mac_id、gameType、jwt/// </summary> public static string unityCallGetInitData(){return "";}/// <summary>/// 让IOS 呼叫重新登录/// </summary>/// <returns></returns>public static void unityCallJumpLogin(){Debug.Log("呼叫 ios重新登录");}/// <summary>/// IOS充值的返回 /// </summary> public static void unityCallJumpToRecharge(string gameStatus, stringreceOBName, string methodName){}/// <summary>/// 关闭当前 IOS活动页/// </summary>public static  void unityCallCloseVC(){}/// <summary>/// 隐私按钮/// </summary>public static void onPrivacyButton(){}/// <summary>/// 储值被点击/// </summary>public static string storedValue(){return "";}/// <summary>/// 切换G/// </summary>/// <returns></returns>public static string ChangeGame(){return "";}#elif UNITY_IOS || UNITY_TVOS //定义对应.mm脚本的 调用接口-----------[DllImport("__Internal")]public static extern string unityCallGetInitData();[DllImport("__Internal")]public static extern void unityCallJumpLogin();[DllImport("__Internal")]public static extern void unityCallJumpToRecharge(string gameStatus, stringreceOBName, string methodName);[DllImport("__Internal")]public static extern void unityCallCloseVC();[DllImport("__Internal")]public static extern void onPrivacyButton();[DllImport("__Internal")]public static extern string storedValue();[DllImport("__Internal")]public static extern string ChangeGame();
#endif}#endregion/// <summary>/// 被安卓调用过来的 统一函数名称  Public void Give_AnCall(string value)/// </summary>public const string Give_AnCall = "Give_AnCall";/// <summary>/// 当处于同一个物体的时候;用来区分函数名称/// </summary>public const string Give_AnCall2 = "Give_AnCall2";/// <summary>/// 关闭app当前页面/// </summary>public void unityCallCloseActivity(){if (Application.platform ==RuntimePlatform.IPhonePlayer|| Application.platform==RuntimePlatform.OSXEditor){Debug.Log("IOS 关闭当前Activity----------");NativeAPI.unityCallCloseVC();//关闭Ios 活动页}else{Debug.Log("关闭当前Activity----------");AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态AndroidJavaObject  s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态s_ActivityContext.Call("unityCallCloseActivity");//关闭页面 }}/// <summary>/// 获取 玩家进入哪个游戏类型 [ 0是推币机 1是连连看 -1是未知类型]/// 并且获取到 baseURL mac_id jwt gameType/// </summary> public IEnumerator unityCallGetInitData(Action<JsonData,string> callBack){int Time = 0;string strData="";string Tips="";try{if (Application.platform ==RuntimePlatform.IPhonePlayer){strData = NativeAPI.unityCallGetInitData();}else{AndroidJavaClass activityClass;AndroidJavaObject s_ActivityContext;activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); //只能调用静态s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity"); //可以调用非静态strData = s_ActivityContext.Call<string>("unityCallGetInitData");}}catch (Exception e){Tips = "Error:" + e;if (callBack != null){callBack(null, Tips);}//跳出协程的执行yield break;}while (string.IsNullOrEmpty(strData))//等待回调{yield return new WaitForSeconds(1);Time++;if (Time >= 10){break; //跳出循环}}//还是没有 收到安卓返回数据  if (string.IsNullOrEmpty(strData)){if (callBack!=null){Tips = "Get the Android Or IOS data timeout";//获取安卓数据超时callBack(null, Tips);} }else{JsonData jsonData = JsonMapper.ToObject(strData);if (callBack!=null){callBack(jsonData, "successful"); }}}/// <summary>/// 跳转到 充值界面 (1.当前游戏场景名称 ,2.物体名称 ,3.安卓返回参数到 哪个函数接收) /// </summary> public void unityCallJumpToRecharge(string ScreenName, string receOBName, string methodName){if (Application.platform ==RuntimePlatform.IPhonePlayer){NativeAPI.unityCallJumpToRecharge(ScreenName,receOBName,methodName);//跳转到 充值}else{Debug.Log("呼叫 安卓跳转充值!----------------");AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态AndroidJavaObject  s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态s_ActivityContext.Call("unityCallJumpToRecharge",ScreenName,receOBName,methodName); }}/// <summary>/// 跳转到 重新登录界面/// </summary>public void unityCallJumpLogin(){if (Application.platform ==RuntimePlatform.IPhonePlayer){NativeAPI.unityCallJumpLogin();//IOS 进入 重新登录页面}else{Debug.Log("跳转到重新登录的Activity--------------");AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态AndroidJavaObject  s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态s_ActivityContext.Call("unityCallJumpLogin");activityClass = null;s_ActivityContext = null;}}/// <summary>/// 显示UnityLog到 安卓调试窗/// </summary>public void unityCallPrintLog(string log){if (Application.platform ==RuntimePlatform.IPhonePlayer){//TODO }else{AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态AndroidJavaObject  s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态s_ActivityContext.Call("unityCallPrintLog",log);}}/// <summary> 打开隐私按钮 </summary>public void onPrivacyButton(){if (Application.platform ==RuntimePlatform.IPhonePlayer){NativeAPI.onPrivacyButton();}else{Debug.Log("打开隐私按钮");}}/// <summary> 打开储值 </summary>public void storedValue(){if (Application.platform == RuntimePlatform.IPhonePlayer){Debug.Log("ios打开储值:"+NativeAPI.storedValue()); }else{Debug.Log("打开储值按钮");if (Application.platform == RuntimePlatform.WindowsEditor){//LogoGM.instance.HeroInfo_PlayCount(5);//默认给+5个//LogoGM.instance.HeroInfoSave();//PC端 增加可玩次数保存}}}/// <summary> 查询是否切换游戏 </summary>/// <returns></returns>public string ChangeGame(){if (Application.platform == RuntimePlatform.IPhonePlayer){return "IOS查询是否切换" + NativeAPI.ChangeGame();}else{return "PC查询游戏切换";}}/// <summary>/// IOS调用Unity的方法:UnitySendMessage("物体名", "函数名", "回调字符串");/// </summary>/// <param name="msg"></param>public void ReceIosMsg(string msg){Debug.Log("IOS 回调的信息");/*//根据游戏的场景划分 确定回调逻辑int scenceId = SceneManager.GetActiveScene().buildIndex;if (string.IsNullOrEmpty(msg)){Debug.Log(scenceId+"场景 收到IOS消息为空字符");}else{string strType;string strCode;//字符串转json对象JsonData jsonData = JsonMapper.ToObject(msg);switch (scenceId){case 0://场景0try{strType = jsonData["type"].ToString();strCode = jsonData["str"].ToString();if (strType=="ChuShiHua"){int code = int.Parse(strCode);if (code==0)//非游戏 静止在这个界面{Debug.Log(scenceId+"场景收到非游戏Code,等待跳转");//SetOrientationPortrait();//设置为竖屏mSpr.gameObject.SetActive(false);TestUpsideDown(1);}else{Debug.Log("正常游戏");toMenu();}}else{Debug.Log(scenceId+"场景 收到的不是初始化字段:"+strType);}}catch (Exception e){Debug.LogError(string.Format("{0} 场景 解析数据出错 原数据:{1}",scenceId,msg));}break;case 1://场景1try{strType = jsonData["type"].ToString();strCode = jsonData["str"].ToString();if (strType == "APPStore_Scuess"){//TODO 储值成功 添加可玩次数Debug.Log("储值成功");HeroInfo_PlayCount(9999);HeroInfoSave();//场景1的储值}else{Debug.Log(scenceId+"场景 收到的不是储值字段:"+strType);}}catch (Exception e){Debug.LogError(string.Format("{0} 场景 解析数据出错 原数据:{1}",scenceId,msg));}break;}}*/}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA-软开-常见八股文(2)-数据库相关

1 Drop Delete Truncate三者之间的区别和联系 drop删除整张表&#xff0c;包括表结构和表数据。用法 drop table 表名 truncate表示清空数据&#xff0c;不会删除表结构。truncate table 表名 delete表示删除数据&#xff0c;不会删除表结构。delete from 表名 where 列名 值…

2023最新版本 FreeRTOS教程 -5-切断驱动和应用的直接关联与多输入的编码思路

在多输入的场景方便添加新的设备如图 总体的思路框图 函数讲解&#xff08;图片太抽象通过这个函数理解&#xff09; 写入自己的队列 统一数据(建议读取自己的队列 再统一到应用的队列 这里图方便省略了) 通过统一的数据做出执行操作 验证 队列为空直接阻塞 通过三个按…

@Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成

问题 Tag和Operation标签失效 但是Schema标签有效 pom依赖 <!-- 接口文档--><!--引入openapi支持--><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><vers…

MySQL - Zero date value prohibited

问题: timestamp字段报Caused by: com.mysql.cj.exceptions.DataReadException: Zero date value prohibited 原因: timestamp字段存入了0值, 超出了最小值1900-01-01 00:00:00, 转Java对象的时候报错 解决: 1.修复或删除原数据 2. mysqlurl 中添加zeroDateTimeBehaviorconve…

【漏洞复现】Drupal XSS漏洞复现

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 复现环境&#xff1a;Vulhub 环境启动后&#xff0c;访问 http://192.168.80.141:8080/ 将会看到drupal的安装页面&#xff0c;一路默认配置下一步安装。因为没有mysql环境&#xff0c;…

Linux ----------------------- 文本处理工具

&#xff08;一&#xff09;绪论 awk、grep、sed和cut 是Linux 操作文本的四大利器&#xff0c;合称文本四大金刚&#xff0c;也是必须掌握的Linux 命令之一。这四个工具的功能各有侧重&#xff1a; awk&#xff1a;功能最强大&#xff0c;用于处理和格式化文本&#xff0c;可…

万宾科技管网水位监测助力智慧城市的排水系统

以往如果要了解城市地下排水管网的水位变化&#xff0c;需要依靠人工巡检或者排查的方式&#xff0c;这不仅加大了人员的工作量&#xff0c;而且也为市政府带来了更多的工作难题。比如人员监管监测不到位或无法远程监控等情况&#xff0c;都会降低市政府对排水管网的管理能力&a…

如何实现多租户系统

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 不知道为什么&#xff0c;最近老是有一些失眠&#xff0c;凌晨睡&#xff0c;两点半还在醒着。脑子里想着自己生…

nodelist 与 HTMLCollection 的区别

原地址 https://cloud.tencent.com/developer/article/2013289 节点与元素 根据 W3C 的 HTML DOM 标准&#xff0c;HTML 文档中的所有内容都是节点&#xff1a; 整个文档是一个文档节点每个 HTML 元素是元素节点HTML 元素内的文本是文本节点每个 HTML 属性是属性节点注释是注…

【ChatOCR】OCR+LLM定制化关键信息抽取(附开源大语言模型汇总整理)

目录 背景技术方案存在的问题及解决思路关键信息提取结果其他解决方案替换文心一言LangChain大型多模态模型&#xff08;Large Multimodal Model, LMM&#xff09; 开源大模型汇总LLaMA —— Meta 大语言模型Stanford Alpaca —— 指令调优的 LLaMA 模型Lit-LLaMA —— 基于 na…

生成式人工智能:网络攻击者手中的破坏性力量

2022 年底&#xff0c;公开可用的生成式人工智能工具的推出使我们进入了人类历史上最大的技术革命之一。 一些人声称它的影响与互联网、手机、智能手机和社交媒体的引入一样大&#xff0c;甚至更大。这些新的生成式人工智能技术的采用和发展速度是我们以前从未见过的。 虽然这…

Spring Task(定时任务)框架

文章目录 一、Spring Task介绍二、cron表达式1.cron表达式介绍2.cron表达式在线生成器 三、fixedDelay四、fixedRate五、initialDelay六、Spring Task的使用1.导入maven坐标spring-context2.启动类添加注解EnableScheduling开启任务调度3.自定义定时任务类 一、Spring Task介绍…