本文适合的情况如下:
Unity客户端人员 与 IOS端研发人员合作的情况
目录
From U3D to 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
#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平台
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;
}
}
*/
}
}