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

2 篇文章 0 订阅

本文适合的情况如下:

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 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平台

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, string
           receOBName, 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, 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
    
    

    /// <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://场景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;
            }
        }
	    */
        
		
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AD_喵了个咪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值