本文适合的情况如下:
Unity客户端人员 与 IOS端研发人员合作的情况
目录
1.unity工程目录创建2个文件 NativeCallProxy.m、NativeCallProxy.h 并且放到Unity工程目录Plugins/iOS/unity_ios_plus目录下
2.创建C#调用脚本 定义对应.mm脚本的 调用接口,调用也如下
由于U3D无法直接调用Objc或者Swift语言声明的接口,幸好U3D的主要语言是C#,因此可以利用C#的特性来访问C语言所定义的接口,然后再通过C接口再调用ObjC的代码(对于Swift代码则还需要使用OC桥接)。
下面演示:利用C#的特性来访问C语言所定义的接口,然后再通过C接口再调用ObjC的代码

NativeCallProxy.m代码内容:
- #import <Foundation/Foundation.h>
- #import "NativeCallProxy.h"
-
- //固定写法
- @implementation FrameworkLibAPI
-
- id<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平台

- 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文件
-
- ///
- /// 呼叫安卓或 IOS 工具类
- ///
- public class CallAndroidOrIos :MonoBehaviour
- {
-
- public static CallAndroidOrIos instance;
- private void Awake()
- {
- instance = this;
- }
-
- #region 关于IOS的操作
-
-
- ///
- /// 模拟 安卓或iOS ,DLL的类;
- ///
- public class NativeAPI
- {
-
- #if UNITY_EDITOR || UNITY_ANDROID
-
- ///
- /// 获取 IOS返回的 json数据 :baseUrl、mac_id、gameType、jwt
- ///
- public static string unityCallGetInitData()
- {
- return "";
- }
-
- ///
- /// 让IOS 呼叫重新登录
- ///
- ///
- public static void unityCallJumpLogin()
- {
- Debug.Log("呼叫 ios重新登录");
- }
-
-
- ///
- /// IOS充值的返回
- ///
- public static void unityCallJumpToRecharge(string gameStatus, string
- receOBName, string methodName)
- {
-
- }
-
-
- ///
- /// 关闭当前 IOS活动页
- ///
- public static void unityCallCloseVC()
- {
-
- }
-
- ///
- /// 隐私按钮
- ///
- public static void onPrivacyButton()
- {
-
-
- }
-
- ///
- /// 储值被点击
- ///
- public static string storedValue()
- {
- return "";
- }
-
- ///
- /// 切换G
- ///
- ///
- 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, string
- receOBName, 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
-
-
-
- ///
- /// 被安卓调用过来的 统一函数名称 Public void Give_AnCall(string value)
- ///
- public const string Give_AnCall = "Give_AnCall";
-
- ///
- /// 当处于同一个物体的时候;用来区分函数名称
- ///
- public const string Give_AnCall2 = "Give_AnCall2";
-
- ///
- /// 关闭app当前页面
- ///
- 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
("currentActivity");//可以调用非静态 - s_ActivityContext.Call("unityCallCloseActivity");//关闭页面
- }
-
-
- }
-
-
-
- ///
- /// 获取 玩家进入哪个游戏类型 [ 0是推币机 1是连连看 -1是未知类型]
- /// 并且获取到 baseURL mac_id jwt gameType
- ///
- public IEnumerator unityCallGetInitData(Action
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
("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");
- }
- }
-
- }
-
-
-
-
- ///
- /// 跳转到 充值界面 (1.当前游戏场景名称 ,2.物体名称 ,3.安卓返回参数到 哪个函数接收)
- ///
- 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
("currentActivity");//可以调用非静态 - s_ActivityContext.Call("unityCallJumpToRecharge",ScreenName,receOBName,methodName);
- }
-
- }
-
-
-
- ///
- /// 跳转到 重新登录界面
- ///
- 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
("currentActivity");//可以调用非静态 - s_ActivityContext.Call("unityCallJumpLogin");
- activityClass = null;
- s_ActivityContext = null;
- }
- }
-
-
-
- ///
- /// 显示UnityLog到 安卓调试窗
- ///
- 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
("currentActivity");//可以调用非静态 - s_ActivityContext.Call("unityCallPrintLog",log);
- }
-
-
-
- }
-
-
- ///
打开隐私按钮 - public void onPrivacyButton()
- {
-
- if (Application.platform ==RuntimePlatform.IPhonePlayer)
- {
- NativeAPI.onPrivacyButton();
- }
- else
- {
- Debug.Log("打开隐私按钮");
- }
- }
-
- ///
打开储值 - 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端 增加可玩次数保存
-
- }
- }
- }
-
- ///
查询是否切换游戏 - ///
- public string ChangeGame()
- {
- if (Application.platform == RuntimePlatform.IPhonePlayer)
- {
- return "IOS查询是否切换" + NativeAPI.ChangeGame();
- }
- else
- {
- return "PC查询游戏切换";
- }
- }
-
-
-
-
- ///
- /// IOS调用Unity的方法:UnitySendMessage("物体名", "函数名", "回调字符串");
- ///
- ///
- 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://场景0
-
- try
- {
- 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://场景1
- try
- {
- 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;
- }
- }
- */
-
-
- }
- }