本文适合的情况如下:

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

#import "NativeCallProxy.h"

//固定写法

@implementation FrameworkLibAPI

id api = NULL;

+(void) registerAPIforNativeCalls:(id) 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

// 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) 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文件

///

/// 呼叫安卓或 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 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("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;

}

}

*/

}

}

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: