当前位置:   article > 正文

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

ios u3d

本文适合的情况如下:

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代码内容:

  1. #import <Foundation/Foundation.h>
  2. #import "NativeCallProxy.h"
  3. //固定写法
  4. @implementation FrameworkLibAPI
  5. id<NativeCallsProtocol> api = NULL;
  6. +(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
  7. {
  8. api = aApi;
  9. }
  10. //固定写法结束
  11. @end
  12. //固定写法
  13. extern "C" {
  14. //void showHostMainWindow(const char* color) { return [api showHostMainWindow:[NSString stringWithUTF8String:color]]; };
  15. //返回字符串的1个函数
  16. const char* unityCallGetInitData(){
  17. NSString* str=[api unityCallGetInitData];
  18. char* ret = nullptr;
  19. // ret = (char*)malloc([str length]+1);
  20. // memcpy(ret, [str UTF8String], ([str length])+1);
  21. ret = (char*)malloc([str length]);
  22. memcpy(ret, [str UTF8String], [str length]);
  23. return ret;
  24. };
  25. //无返回的1个函数
  26. void unityCallJumpLogin(){
  27. return [api unityCallJumpLogin];
  28. };
  29. //无返回、传入字符串的函数
  30. void unityCallJumpToRecharge(const char* gameStatus,const char* receOBName,const char* methodName){
  31. return [api unityCallJumpToRecharge:[NSString stringWithUTF8String:gameStatus] :[NSString stringWithUTF8String:receOBName] :[NSString stringWithUTF8String:methodName]];
  32. };
  33. void unityCallCloseVC(){
  34. return [api unityCallCloseVC];
  35. };
  36. //隱私按鈕
  37. void onPrivacyButton(){
  38. return [api onPrivacyButton];
  39. }
  40. //儲值按鈕
  41. const char* storedValue(){
  42. NSString* str=[api storedValue];
  43. char* ret = nullptr;
  44. ret = (char*)malloc([str length]);
  45. memcpy(ret, [str UTF8String], [str length]);
  46. return ret;
  47. }
  48. //切换游戏
  49. const char* ChangeGame(){
  50. NSString* str=[api ChangeGame];
  51. char* ret = nullptr;
  52. ret = (char*)malloc([str length]);
  53. memcpy(ret, [str UTF8String], [str length]);
  54. return ret;
  55. }
  56. }
  57. //extern "C" {
  58. //
  59. //}

NativeCallProxy.h代码内容

  1. // [!] important set UnityFramework in Target Membership for this file
  2. // [!] and set Public header visibility
  3. //固定写法
  4. #import <Foundation/Foundation.h>
  5. // NativeCallsProtocol defines protocol with methods you want to be called from managed
  6. @protocol NativeCallsProtocol
  7. @required
  8. // other methods 自定义方法
  9. /**
  10. 获取初始json数据:baseUrl、mac_id、gameType、jwt 【对应mm文件的自定义函数名】
  11. */
  12. -(NSString*)unityCallGetInitData;
  13. /**
  14. 重新登录 【对应mm文件的自定义函数名的接口】
  15. */
  16. -(void)unityCallJumpLogin;
  17. /**
  18. 跳充值页前保存数据,充值页返回后把保存的数据发信息给unity 【对应mm文件的自定义函数名的接口】
  19. */
  20. -(void)unityCallJumpToRecharge:(NSString*) gameStatus :(NSString*) receOBName :(NSString*) methodName;
  21. //ios——关闭vc 【对应mm文件的自定义函数名的接口】
  22. -(void)unityCallCloseVC;
  23. //隱私按鈕 【对应mm文件的自定义函数名的接口】
  24. -(void)onPrivacyButton;
  25. //储值按钮 【对应mm文件的自定义函数名的接口】
  26. -(NSString*)storedValue;
  27. //ch Game 【对应mm文件的自定义函数名的接口】
  28. -(NSString*)ChangeGame;
  29. //自定义方法结束
  30. @end
  31. //以下为固定写法
  32. __attribute__ ((visibility("default")))
  33. @interface FrameworkLibAPI : NSObject
  34. // call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
  35. +(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi;
  36. @end

勾选iOS平台

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

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using LitJson;
  5. using UnityEngine;
  6. using UnityEngine.UI;
  7. using System.Runtime.InteropServices;
  8. using UnityEngine.SceneManagement; //引入 这个命名空间,让unity可以使用 Assets/Plugins/iOS 或 Android/ 这里的dll文件
  9. /// <summary>
  10. /// 呼叫安卓或 IOS 工具类
  11. /// </summary>
  12. public class CallAndroidOrIos :MonoBehaviour
  13. {
  14. public static CallAndroidOrIos instance;
  15. private void Awake()
  16. {
  17. instance = this;
  18. }
  19. #region 关于IOS的操作
  20. /// <summary>
  21. /// 模拟 安卓或iOS ,DLL的类;
  22. /// </summary>
  23. public class NativeAPI
  24. {
  25. #if UNITY_EDITOR || UNITY_ANDROID
  26. /// <summary>
  27. /// 获取 IOS返回的 json数据 :baseUrl、mac_id、gameType、jwt
  28. /// </summary>
  29. public static string unityCallGetInitData()
  30. {
  31. return "";
  32. }
  33. /// <summary>
  34. /// 让IOS 呼叫重新登录
  35. /// </summary>
  36. /// <returns></returns>
  37. public static void unityCallJumpLogin()
  38. {
  39. Debug.Log("呼叫 ios重新登录");
  40. }
  41. /// <summary>
  42. /// IOS充值的返回
  43. /// </summary>
  44. public static void unityCallJumpToRecharge(string gameStatus, string
  45. receOBName, string methodName)
  46. {
  47. }
  48. /// <summary>
  49. /// 关闭当前 IOS活动页
  50. /// </summary>
  51. public static void unityCallCloseVC()
  52. {
  53. }
  54. /// <summary>
  55. /// 隐私按钮
  56. /// </summary>
  57. public static void onPrivacyButton()
  58. {
  59. }
  60. /// <summary>
  61. /// 储值被点击
  62. /// </summary>
  63. public static string storedValue()
  64. {
  65. return "";
  66. }
  67. /// <summary>
  68. /// 切换G
  69. /// </summary>
  70. /// <returns></returns>
  71. public static string ChangeGame()
  72. {
  73. return "";
  74. }
  75. #elif UNITY_IOS || UNITY_TVOS
  76. //定义对应.mm脚本的 调用接口-----------
  77. [DllImport("__Internal")]
  78. public static extern string unityCallGetInitData();
  79. [DllImport("__Internal")]
  80. public static extern void unityCallJumpLogin();
  81. [DllImport("__Internal")]
  82. public static extern void unityCallJumpToRecharge(string gameStatus, string
  83. receOBName, string methodName);
  84. [DllImport("__Internal")]
  85. public static extern void unityCallCloseVC();
  86. [DllImport("__Internal")]
  87. public static extern void onPrivacyButton();
  88. [DllImport("__Internal")]
  89. public static extern string storedValue();
  90. [DllImport("__Internal")]
  91. public static extern string ChangeGame();
  92. #endif
  93. }
  94. #endregion
  95. /// <summary>
  96. /// 被安卓调用过来的 统一函数名称 Public void Give_AnCall(string value)
  97. /// </summary>
  98. public const string Give_AnCall = "Give_AnCall";
  99. /// <summary>
  100. /// 当处于同一个物体的时候;用来区分函数名称
  101. /// </summary>
  102. public const string Give_AnCall2 = "Give_AnCall2";
  103. /// <summary>
  104. /// 关闭app当前页面
  105. /// </summary>
  106. public void unityCallCloseActivity()
  107. {
  108. if (Application.platform ==RuntimePlatform.IPhonePlayer|| Application.platform==RuntimePlatform.OSXEditor)
  109. {
  110. Debug.Log("IOS 关闭当前Activity----------");
  111. NativeAPI.unityCallCloseVC();//关闭Ios 活动页
  112. }
  113. else
  114. {
  115. Debug.Log("关闭当前Activity----------");
  116. AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态
  117. AndroidJavaObject s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态
  118. s_ActivityContext.Call("unityCallCloseActivity");//关闭页面
  119. }
  120. }
  121. /// <summary>
  122. /// 获取 玩家进入哪个游戏类型 [ 0是推币机 1是连连看 -1是未知类型]
  123. /// 并且获取到 baseURL mac_id jwt gameType
  124. /// </summary>
  125. public IEnumerator unityCallGetInitData(Action<JsonData,string> callBack)
  126. {
  127. int Time = 0;
  128. string strData="";
  129. string Tips="";
  130. try
  131. {
  132. if (Application.platform ==RuntimePlatform.IPhonePlayer)
  133. {
  134. strData = NativeAPI.unityCallGetInitData();
  135. }
  136. else
  137. {
  138. AndroidJavaClass activityClass;
  139. AndroidJavaObject s_ActivityContext;
  140. activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); //只能调用静态
  141. s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity"); //可以调用非静态
  142. strData = s_ActivityContext.Call<string>("unityCallGetInitData");
  143. }
  144. }
  145. catch (Exception e)
  146. {
  147. Tips = "Error:" + e;
  148. if (callBack != null)
  149. {
  150. callBack(null, Tips);
  151. }
  152. //跳出协程的执行
  153. yield break;
  154. }
  155. while (string.IsNullOrEmpty(strData))//等待回调
  156. {
  157. yield return new WaitForSeconds(1);
  158. Time++;
  159. if (Time >= 10)
  160. {
  161. break; //跳出循环
  162. }
  163. }
  164. //还是没有 收到安卓返回数据
  165. if (string.IsNullOrEmpty(strData))
  166. {
  167. if (callBack!=null)
  168. {
  169. Tips = "Get the Android Or IOS data timeout";//获取安卓数据超时
  170. callBack(null, Tips);
  171. }
  172. }
  173. else
  174. {
  175. JsonData jsonData = JsonMapper.ToObject(strData);
  176. if (callBack!=null)
  177. {
  178. callBack(jsonData, "successful");
  179. }
  180. }
  181. }
  182. /// <summary>
  183. /// 跳转到 充值界面 (1.当前游戏场景名称 ,2.物体名称 ,3.安卓返回参数到 哪个函数接收)
  184. /// </summary>
  185. public void unityCallJumpToRecharge(string ScreenName, string receOBName, string methodName)
  186. {
  187. if (Application.platform ==RuntimePlatform.IPhonePlayer)
  188. {
  189. NativeAPI.unityCallJumpToRecharge(ScreenName,receOBName,methodName);//跳转到 充值
  190. }
  191. else
  192. {
  193. Debug.Log("呼叫 安卓跳转充值!----------------");
  194. AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态
  195. AndroidJavaObject s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态
  196. s_ActivityContext.Call("unityCallJumpToRecharge",ScreenName,receOBName,methodName);
  197. }
  198. }
  199. /// <summary>
  200. /// 跳转到 重新登录界面
  201. /// </summary>
  202. public void unityCallJumpLogin()
  203. {
  204. if (Application.platform ==RuntimePlatform.IPhonePlayer)
  205. {
  206. NativeAPI.unityCallJumpLogin();//IOS 进入 重新登录页面
  207. }
  208. else
  209. {
  210. Debug.Log("跳转到重新登录的Activity--------------");
  211. AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态
  212. AndroidJavaObject s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态
  213. s_ActivityContext.Call("unityCallJumpLogin");
  214. activityClass = null;
  215. s_ActivityContext = null;
  216. }
  217. }
  218. /// <summary>
  219. /// 显示UnityLog到 安卓调试窗
  220. /// </summary>
  221. public void unityCallPrintLog(string log)
  222. {
  223. if (Application.platform ==RuntimePlatform.IPhonePlayer)
  224. {
  225. //TODO
  226. }
  227. else
  228. {
  229. AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");//只能调用静态
  230. AndroidJavaObject s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");//可以调用非静态
  231. s_ActivityContext.Call("unityCallPrintLog",log);
  232. }
  233. }
  234. /// <summary> 打开隐私按钮 </summary>
  235. public void onPrivacyButton()
  236. {
  237. if (Application.platform ==RuntimePlatform.IPhonePlayer)
  238. {
  239. NativeAPI.onPrivacyButton();
  240. }
  241. else
  242. {
  243. Debug.Log("打开隐私按钮");
  244. }
  245. }
  246. /// <summary> 打开储值 </summary>
  247. public void storedValue()
  248. {
  249. if (Application.platform == RuntimePlatform.IPhonePlayer)
  250. {
  251. Debug.Log("ios打开储值:"+NativeAPI.storedValue());
  252. }
  253. else
  254. {
  255. Debug.Log("打开储值按钮");
  256. if (Application.platform == RuntimePlatform.WindowsEditor)
  257. {
  258. //LogoGM.instance.HeroInfo_PlayCount(5);//默认给+5个
  259. //LogoGM.instance.HeroInfoSave();//PC端 增加可玩次数保存
  260. }
  261. }
  262. }
  263. /// <summary> 查询是否切换游戏 </summary>
  264. /// <returns></returns>
  265. public string ChangeGame()
  266. {
  267. if (Application.platform == RuntimePlatform.IPhonePlayer)
  268. {
  269. return "IOS查询是否切换" + NativeAPI.ChangeGame();
  270. }
  271. else
  272. {
  273. return "PC查询游戏切换";
  274. }
  275. }
  276. /// <summary>
  277. /// IOS调用Unity的方法:UnitySendMessage("物体名", "函数名", "回调字符串");
  278. /// </summary>
  279. /// <param name="msg"></param>
  280. public void ReceIosMsg(string msg)
  281. {
  282. Debug.Log("IOS 回调的信息");
  283. /*
  284. //根据游戏的场景划分 确定回调逻辑
  285. int scenceId = SceneManager.GetActiveScene().buildIndex;
  286. if (string.IsNullOrEmpty(msg))
  287. {
  288. Debug.Log(scenceId+"场景 收到IOS消息为空字符");
  289. }
  290. else
  291. {
  292. string strType;
  293. string strCode;
  294. //字符串转json对象
  295. JsonData jsonData = JsonMapper.ToObject(msg);
  296. switch (scenceId)
  297. {
  298. case 0://场景0
  299. try
  300. {
  301. strType = jsonData["type"].ToString();
  302. strCode = jsonData["str"].ToString();
  303. if (strType=="ChuShiHua")
  304. {
  305. int code = int.Parse(strCode);
  306. if (code==0)//非游戏 静止在这个界面
  307. {
  308. Debug.Log(scenceId+"场景收到非游戏Code,等待跳转");
  309. //SetOrientationPortrait();//设置为竖屏
  310. mSpr.gameObject.SetActive(false);
  311. TestUpsideDown(1);
  312. }
  313. else
  314. {
  315. Debug.Log("正常游戏");
  316. toMenu();
  317. }
  318. }
  319. else
  320. {
  321. Debug.Log(scenceId+"场景 收到的不是初始化字段:"+strType);
  322. }
  323. }
  324. catch (Exception e)
  325. {
  326. Debug.LogError(string.Format("{0} 场景 解析数据出错 原数据:{1}",scenceId,msg));
  327. }
  328. break;
  329. case 1://场景1
  330. try
  331. {
  332. strType = jsonData["type"].ToString();
  333. strCode = jsonData["str"].ToString();
  334. if (strType == "APPStore_Scuess")
  335. {
  336. //TODO 储值成功 添加可玩次数
  337. Debug.Log("储值成功");
  338. HeroInfo_PlayCount(9999);
  339. HeroInfoSave();//场景1的储值
  340. }
  341. else
  342. {
  343. Debug.Log(scenceId+"场景 收到的不是储值字段:"+strType);
  344. }
  345. }
  346. catch (Exception e)
  347. {
  348. Debug.LogError(string.Format("{0} 场景 解析数据出错 原数据:{1}",scenceId,msg));
  349. }
  350. break;
  351. }
  352. }
  353. */
  354. }
  355. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/48737
推荐阅读
相关标签
  

闽ICP备14008679号