7掀鹅、與iOS散休、Android的交互 高級(jí)篇

本文屬于「Unity與iOS、Android平臺(tái)的整合」系列文章之一乐尊,轉(zhuǎn)載請注明出處戚丸。主要講解如何優(yōu)雅地實(shí)現(xiàn)Unity與iOS、Android的交互扔嵌。

零昏滴、前言

市面上提供的SDK基本是原生iOS、Android对人,在Unity接入過程中,往往不是簡簡單單地一次調(diào)用拂共,而是成套的原生API接入牺弄,需要一套完整的解決方案來處理這些問題。
在此宜狐,將自己的方案提出势告,意為拋磚引玉,如果大家有其他思路還望留言交流抚恒。
該解決方案的是對(duì)基礎(chǔ)原理進(jìn)行的拓展咱台。
4、與iOS俭驮、Android的交互 理論篇
5回溺、與iOS、Android的交互 實(shí)踐篇——主動(dòng)調(diào)用
6混萝、與iOS遗遵、Android的交互 實(shí)踐篇——傳遞參數(shù)

一、需求分析

實(shí)際項(xiàng)目使用中逸嘀,我們希望

  • 使用C#代碼調(diào)用相關(guān)功能
  • 在調(diào)用時(shí)不需要區(qū)分具體平臺(tái)
  • 在編輯器模式下進(jìn)行模擬測試
  • 實(shí)現(xiàn)復(fù)雜類型參數(shù)相互傳遞
  • 實(shí)現(xiàn)監(jiān)聽
  • 實(shí)現(xiàn)回調(diào)
  • ……

二车要、方案設(shè)計(jì)

<<<需求:

  • 使用C#代碼調(diào)用相關(guān)功能

>>>方案:

將代碼根據(jù)職責(zé)進(jìn)行分層:

  • 上層邏輯(C#)
  • 供上層邏輯調(diào)用的接口(C#)
  • 調(diào)用SDK的接口(C++、Java)
  • SDK API(OC崭倘、Java)

<<<需求:

  • 在調(diào)用時(shí)不需要區(qū)分具體平臺(tái)
  • 在編輯器模式下進(jìn)行模擬測試

>>>方案:

將上一個(gè)需求的方案進(jìn)行擴(kuò)充:

  • 供上層邏輯調(diào)用的接口(C#)翼岁,使用編譯開關(guān)在函數(shù)內(nèi)部根據(jù)平臺(tái)區(qū)別調(diào)用
    public void Login()
    {
        Login_();
    }
    #if UNITY_EDITOR
    private static void Login_()
    {
        Debug.Log("SDK Login");
    }
    #elif UNITY_IOS
    [DllImport("__Internal")]private static extern void Login_();
    #elif UNITY_ANDROID
private static void Login_() 
{
    using (AndroidJavaClass jc = new AndroidJavaClass("xxx.xxx.xxx))
    {
        jc.CallStatic("Login_"); 
    }
}
    #endif

<<<需求:

  • 實(shí)現(xiàn)復(fù)雜類型參數(shù)相互傳遞

>>>方案:

  • 使用Json序列化、反序列化相關(guān)類型
  • 相互傳遞JSON字符串
public class Message
{
    public int id;
    public string name;
    public static string ToJson(Message msg)
    {
        return Json.Serialize(msg);
    }
    public static Message FromJson(string json)
    {
        return Json.DeSerialize<Message>(json);
    }
}
public void SetLoginInfo(Message msg)
{
    SetLoginInfo_(Message.ToJson(msg));
}
#if UNITY_EDITOR
private static void SetLoginInfo_(string msg)
{
    Debug.Log("SDK SetLoginInfo" + msg);
}
#elif UNITY_IOS
[DllImport("__Internal")]private static extern void SetLoginInfo_(string msg);
#elif UNITY_ANDROID
private static void SetLoginInfo_()
{
    using (AndroidJavaClass jc = new AndroidJavaClass("xxx.xxx.xxx))
    {
        jc.CallStatic("SetLoginInfo_", msg); 
    }
}
#endif
public Message GetLoginInfo()
{
    Message.FromJson(GetLoginInfo_());
}
#if UNITY_EDITOR
private static string GetLoginInfo_()
{
    return "{\"id\":1,\"name\":\"abc\"}";
}
#elif UNITY_IOS
[DllImport("__Internal")]private static extern string GetLoginInfo_();
#elif UNITY_ANDROID
private static string GetLoginInfo_()
{
    using (AndroidJavaClass jc = new AndroidJavaClass("xxx.xxx.xxx))
    {
        return jc.CallStatic<string>("GetLoginInfo_"); 
    }
}
#endif

<<<需求:

  • 實(shí)現(xiàn)監(jiān)聽

>>>方案:

  • 供上層邏輯調(diào)用的接口(C#)司光,提供監(jiān)聽
  • 調(diào)用SDK的接口(C++琅坡、Java),注冊原生API的監(jiān)聽
  • 使用UnitySendMessage調(diào)用指定C#方法從而觸發(fā)C#層的監(jiān)聽
  • 使用唯一的GameObject來負(fù)責(zé)接收UnitySendMessage
    供上層邏輯調(diào)用的接口(C#)
public class XXXSDKEventHandler : Monobehaviour
{
    public event Action onLogin;
    public void OnLogin()
    {
        if(onLogin != null)
        {
            onLogin();
        }
    }
}
public class XXXSDKManager
{
    private XXXSDKEventHandler handler;
    public XXXSDKManager()
    {
        handler = new GameObject("XXXSDKEventHandler").AddComponent<XXXSDKEventHandler>();
        Object.DontDestroyOnLoad(handler.gameObject);
    }
    public event Action onLogin
    {
        add { handler.onLogin += value; }
        remove { handler.onLogin -= value; }
    }
}

調(diào)用SDK的接口(C++)

void OnLogin(){
    UnitySendMessage("XXXSDKEventHandler", "OnLogin", "");
}

調(diào)用SDK的接口(Java)

void OnLogin(){
    UnityPlayer.UnitySendMessage("XXXSDKEventHandler", "OnLogin", "");
}

<<<需求:

  • 實(shí)現(xiàn)回調(diào)

>>>方案:

  • 供上層邏輯調(diào)用的接口(C#)飘庄,緩存回調(diào)并分配回調(diào)ID
  • 調(diào)用SDK的接口(C++脑蠕、Java),接收回調(diào)ID
  • 使用UnitySendMessage調(diào)用指定C#方法從而觸發(fā)C#層的回調(diào)
  • 使用唯一的GameObject來負(fù)責(zé)接收UnitySendMessage
public class XXXSDKEventHandler : Monobehaviour
{
    private int cba_key = 0;
    private Dictionary<int, Action> cbas = new Dictionary<int, Action>();
    public int AddCallbackAction(Action action)
    {
        cbas.Add(cba_key, action);
        return cba_key++;
    }
    private void Receiver(string jsonMessage)
    {
        JsonObject jo = Json.DeserializeObject<JsonObject>(jsonMessage);
        int key = int.Parse(jo["cba_key"].ToString());
        if (!cbas.ContainsKey(key)) { return; }
        Action<bool> action = cbas[key];
        if (action != null) { action(result); }
        cbas.Remove(key);
    }
    #region 延時(shí)回調(diào)
    Queue<string> callbackQueue = new Queue<string>();
    private void MessageHandle(string json)
    {
        JsonObject jo = Json.DeserializeObject<JsonObject>(json);
        string funcName = jo["funcName"].ToString();
        string message = jo["message"].ToString();
        this.callbackQueue.Enqueue(funcName);
        this.callbackQueue.Enqueue(message);
    }
    void Update()
    {
        while (true)
        {
            yield return null;
            while (callbackQueue.Count >= 2)
            {
                SendMessage(this.callbackQueue.Dequeue(), this.callbackQueue.Dequeue());
            }
        }
    }
    #endregion
}
public class XXXSDKManager
{
    private XXXSDKEventHandler handler;
    public XXXSDKManager()
    {
        handler = new GameObject("XXXSDKEventHandler").AddComponent<XXXSDKEventHandler>();
        Object.DontDestroyOnLoad(handler.gameObject);
    }
    public Login(Action onFinish)
    {
        Login_(handle.AddCallbackAction(onFinish));
    }
    #if UNITY_EDITOR
    private static void Login_(int callbackID)
    {
        Debug.Log("SDK Login");
        handler.SendMessage("Receiver","{\"funcName\":\"Receiver\",\"message\":\"{\\\"cba_key\\\":\\\"" + callbackID + "\\\"}\"}");
    }
    #elif UNITY_IOS
    [DllImport("__Internal")]private static extern void Login_(int callbackID);
    #elif UNITY_ANDROID
    private static void Login_(int callbackID) 
    {
        using (AndroidJavaClass jc = new AndroidJavaClass("xxx.xxx.xxx))
        {
            jc.CallStatic("Login_", callbackID); 
        }
    }
}

SDK的回調(diào)接口(C++)

void Login_(int callbackID){
    //處理xxx,最后調(diào)用以下
    UnitySendMessage("XXXSDKEventHandler", "OnLogin", [NSString stringWithFormat:@"{\"funcName\":\"Receiver\",\"message\":\"{\\\"cba_key\\\":\\\"%d\\\"}\"}", callbackID]);
}

SDK的回調(diào)接口(Java)

void Login_(int callbackID){
    //處理xxx谴仙,最后調(diào)用以下
    UnityPlayer.UnitySendMessage("XXXSDKEventHandler", "OnLogin", "{\"funcName\":\"Receiver\",\"message\":\"{\\\"cba_key\\\":\\\"" + callbackID + "\\\"}\"}");
}

三迂求、收個(gè)尾

以上內(nèi)容為Unity與iOS/Android原生SDK交互的整套解決方案,能夠解決復(fù)雜的原生SDK交互需求晃跺,在項(xiàng)目中也經(jīng)歷過實(shí)踐揩局,親測可用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掀虎,一起剝皮案震驚了整個(gè)濱河市凌盯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烹玉,老刑警劉巖驰怎,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異二打,居然都是意外死亡县忌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門继效,熙熙樓的掌柜王于貴愁眉苦臉地迎上來症杏,“玉大人,你說我怎么就攤上這事瑞信±鞑” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵凡简,是天一觀的道長逼友。 經(jīng)常有香客問我,道長秤涩,這世上最難降的妖魔是什么翁逞? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮溉仑,結(jié)果婚禮上挖函,老公的妹妹穿的比我還像新娘。我一直安慰自己浊竟,他們只是感情好怨喘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著振定,像睡著了一般必怜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上后频,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天梳庆,我揣著相機(jī)與錄音暖途,去河邊找鬼。 笑死膏执,一個(gè)胖子當(dāng)著我的面吹牛驻售,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播更米,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼欺栗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了征峦?” 一聲冷哼從身側(cè)響起迟几,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎栏笆,沒想到半個(gè)月后类腮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛉加,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年存哲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片七婴。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖察滑,靈堂內(nèi)的尸體忽然破棺而出打厘,到底是詐尸還是另有隱情,我是刑警寧澤贺辰,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布户盯,位于F島的核電站,受9級(jí)特大地震影響饲化,放射性物質(zhì)發(fā)生泄漏莽鸭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一吃靠、第九天 我趴在偏房一處隱蔽的房頂上張望硫眨。 院中可真熱鬧,春花似錦巢块、人聲如沸礁阁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姥闭。三九已至,卻和暖如春越走,著一層夾襖步出監(jiān)牢的瞬間棚品,已是汗流浹背靠欢。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铜跑,地道東北人门怪。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像疼进,于是被迫代替她去往敵國和親薪缆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理伞广,服務(wù)發(fā)現(xiàn)拣帽,斷路器,智...
    卡卡羅2017閱讀 134,629評(píng)論 18 139
  • 前言 最近在實(shí)驗(yàn)室做了一個(gè)項(xiàng)目嚼锄,用到了藍(lán)牙通訊和U3D的交互减拭,都有很多坑,如:IOS與Unity3D界面之間的跳轉(zhuǎn)...
    Larrycal閱讀 23,623評(píng)論 34 53
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉区丑,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,686評(píng)論 0 9
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法拧粪,類相關(guān)的語法,內(nèi)部類的語法沧侥,繼承相關(guān)的語法可霎,異常的語法,線程的語...
    子非魚_t_閱讀 31,598評(píng)論 18 399
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程宴杀,因...
    小菜c閱讀 6,365評(píng)論 0 17