標籤:
一、前言
接入Android SDK正式告一段落,在這段時間裡面,依次接入了華為、應用寶、小米、360等等大大小小十來個SDK,也算對Unity接入渠道SDK有了較為全面的理解,對各個渠道的坑也算深有體會。。。。在接入過程中時間比較緊張,沒辦法抽空來進行總結深思。今天正好有空,便對之前的接入SDK的代碼進行了一次重構,寫了一個比較通用的Unity接入Android SDK的中介軟體,前人栽樹,後人乘涼。
進入正題
如果有對一些只是有疑問的,可以看看我之前的三篇文章:
傳送門:
Unity3d Android SDK接入解析(一)Unity3d 與 Android之間的互相調用:
http://blog.csdn.net/yang8456211/article/details/51331358
Unity3d Android SDK接入解析(二)Unity3d Android SDK的設計與兩種接入方式
http://blog.csdn.net/yang8456211/article/details/51356193
Unity3d Android SDK接入解析(三)接入Android Library的理解(愛貝雲支付為例)
http://blog.csdn.net/yang8456211/article/details/51435465
二、關於中介軟體的一些思考2.1 為什麼不用第三方平台
為什麼要自己做一個Unity接入Android SDK的中介軟體呢?市面上例如Anysdk、易接這種第三方渠道是可以滿足接入一次,產生大部分的SDK的,但是由於大渠道的審查越來越嚴格,已經禁止了這種第三方的平台SDK。因此,這些大渠道則必須由我們自己來接入了(不過二、三線渠道仍然是可以用第三方進行接入的),如果每個渠道都使用一個單獨工程來管理,這無疑是一種非常浪費時間而且難以維護的事情,因此我想做的就是一個Unity的接入Android SDK的外掛程式,所有的SDK的邏輯都封裝好在Android層面,不同的遊戲都可以按照相同的規則來接入進來,只需要調用通用的介面,準備好對應的資源即可。
2.2 怎麼樣做方便
我希望把這個中介軟體做的盡量能夠通用,而且能夠方便拆分、迭代。對Unity層面邏輯透明,只需要關注介面調用的時機和傳入的參數。
—— 通用,形式簡單 ——
先說說通用吧:
對於Unity遊戲來說,通常以Plugins的形式接入SDK比較方便,所以從這個思路出發,中介軟體的形式,我決定做成了jar包,而不是一個Library的工程,jar包裡面只包含純程式碼,沒有資源和任何設定檔,調用方只用把jar包放在 Plugins/Android/libs 裡面就可以使用了。對於不同遊戲來說,沒有差別。
最終的形式,就是一個uasdkinter的jar包,所有的SDK的邏輯會整合在這個jar裡面。
形式簡單的也有一層含義是,方便整合和拆分:
因此在package的設計上,每個渠道獨立一個package放渠道代碼,理論上我們匯出jar包的時候,直接把所有渠道的代碼都打進jar包就可以了,因為每次代碼會根據傳入的channel執行唯一的渠道,其他代碼也就放在那了。
但是有些渠道會進行代碼檢測,例如360,會檢測到包內含有小米支付相關的代碼,審核不過,對應我們只需要在打jar的時候,勾選去掉對應的package就可以了。(因為是重構的代碼架構,並沒有包含很多sdk)
—— 只關注SDK商務邏輯 ——
中介軟體本身,只包含設計思想和一個簡潔的架構。在接入渠道SDK的時候,我們只需要把渠道的SDK代碼以一定的規則加入到中介軟體中即可。
所以這個中介軟體必須要健壯,架構寫好之後,再添加新的SDK代碼必須比較方便,無需對架構做大的改動。
因此我使用介面來實現,每個渠道SDK有兩個class,一個管理帳號資訊,一個管理支付資訊,帳號與支付分離。
帳號介面:
public interface UAGameInterf { // 初始化 public void init(JSONObject sJson); // 登入 public void login(JSONObject sJson); // 登出 public void logout(); // 離開遊戲 public void exit(); // 初始化參數檢查 public boolean initParams(JSONObject sJson); // 設定生命週期的函數 public void lifeCycle(int status); // 儲存使用者資訊 public void upUserInfo(JSONObject sJson);}
支付介面:
public interface UAPayInterf { // 支付 public void pay(); // 初始化參數 public boolean initParams(JSONObject sJson);}
在添加SDK的時候,只需要建立帳號class和支付的class,分別實現對應的介面,而不用管外層是怎麼調用的,訊息是怎麼返回Unity的,而只用具體的實現每個介面即可,做到只關注SDK的商務邏輯(具體介面的設計說明後面詳敘)。
—— 調用簡單 ——
調用上,C#初始化“包名+類名”的AndroidJavaClass對象,使用這個對象來調用對應功能,區別於建立一個Activity繼承UnityPlayerActivity 的模式,這個方法避免了一系列的蛋疼的問題(例如中介軟體工程需要和遊戲工程的包名一樣)
C#的調用:
中介軟體工程的包名是: com.uainter.main
介面類名是:UAMain
因此可以在C#建立AndroidJavaClass對象:
AndroidJavaClass ajc_SDKCall ajc_SDKCall = new AndroidJavaClass("com.uainter.main.UAMain");
為了方便調用,把對外的介面都做成了靜態方法,所以用CallStatic去調用,因為每個渠道需要的參數類型和參數個數不確定,因為把傳入參數定義成了一個Json。
例如調用小米渠道的Init方法:
小米渠道需要3個參數:appid、appkey、islandscape(登入與支付橫屏還是豎屏顯示)
string json = "{‘channel‘:‘11‘,‘debugmode‘:1,‘appid‘:‘xxx‘,‘appkey‘:‘xxx‘,‘islandscape‘:false}";ajc_SDKCall.CallStatic("uaInit",json);
Login方法:
string json = "{}";ajc_SDKCall.CallStatic("uaLogin",json);
對於每個可能會有參數傳入的方法,都設定了一個json對象作為參數,例如login方法,在接入應用寶的時候,需要在json資料中傳入一個platform來判斷是登入還是QQ。
中間鍵暴露出的介面有以下幾個:
2.3 一些特殊操作的思考與處理Activity生命週期的處理
理論我希望做到不需要修改啟動的Activity,所以Activity生命週期的處理,放在了C#去控制,Android提供介面public void lifeCycle(int status); 在這個介面裡面處理渠道SDK需要做的生命週期操作。
例如華為:
(Android 代碼)
public void lifeCycle(int status) { if (getActivity() == null) { DybGSdkUtil.E("還未Init初始化,不執行生命週期操作 "); return; } switch (status) { case DybGSdkConstants.onStart: break; case DybGSdkConstants.onResume: BuoyOpenSDK.getIntance().showSmallWindow(getActivity()); break; case DybGSdkConstants.onPause: BuoyOpenSDK.getIntance().hideSmallWindow(getActivity()); BuoyOpenSDK.getIntance().hideBigWindow(getActivity()); break; case DybGSdkConstants.onStop: break; case DybGSdkConstants.onDestroy: OpenHwID.releaseResouce(); BuoyOpenSDK.getIntance().destroy(getActivity()); break; default: break; } }
(C#調用)
void OnApplicationPause(bool isPause) { if (isPause) { string json = "{‘status‘:‘3‘}"; ajc_SDKCall.CallStatic("uaLifeCycle",json); } } void OnApplicationFocus(bool isFocus) { if (isFocus) { if (ajc_SDKCall != null){ string json = "{‘status‘:‘1‘}"; ajc_SDKCall.CallStatic("uaLifeCycle",json); json = "{‘status‘:‘2‘}"; ajc_SDKCall.CallStatic("uaLifeCycle",json); } } } void OnApplicationQuit() { string json = "{‘status‘:‘5‘}"; ajc_SDKCall.CallStatic("uaLifeCycle",json); }
(對應的status和生命週期)
// Android Activity生命週期 public static final int onStart = 1; public static final int onResume = 2; public static final int onPause = 3; public static final int onStop = 4; public static final int onDestroy = 5; public static final int onRestart = 6;
實在遇到需要Activity的地方怎麼處理?
只有在接入應用寶的時候,遇到了需要接入Activity的兩個方法onNewIntent和onActivityResult時,需要接受qq和的回調,這種情況我也沒有想到什麼好辦法,只有建立一個Activity,然後實現這個兩個方法,並修改這個Activity為AndroidManifest裡面的啟動Activity。
遇到需要自定application的情況呢?
跟Activity類似,這個時候我們建立一個Application即可。
大部分的SDK方法需要在UI線程中調用
這個之前有說過,在這裡只是列出來不詳述了:
例如登入:
public static void uaLogin(String jsonString) { try { final JSONObject sJson = new JSONObject(jsonString); final UAGameInterf uaManager = getSdkObj(sChannel); activity.runOnUiThread(new Runnable() { @Override public void run() { uaManager.login(sJson); } }); } catch (JSONException e) { e.printStackTrace(); } }
怎麼發送訊息回Unity
// 發送訊息回Unity3d public static void dybCallback(JSONObject rjson) { UnityPlayer.UnitySendMessage(UAMain.callBackobj, UAMain.callBackFun, rjson.toString()); }
其中callBackobj 和 callBackFun,分別對應接收傳回值的對象的名稱和回調方法。(此處我是寫死的常量,也可以通過在init中傳入對應的key來動態修改這兩個值)
可以看到,返回的也是一個json,裡麵包括了一個“callbackType”的key用來判斷是哪個介面回調的結果,例如Init回調:
JSONObject jsonObj = new JSONObject(); String code = "1"; jsonObj.put("callbackType", "Init"); jsonObj.put("code", code); UAMain.dybCallback(jsonObj);
三、中介軟體對外介面說明
public static void uaInit(String jsonString)
主要用於各個渠道SDK的初始化,傳入的json字串中,必須包含的是,debugMode和channel這兩個key,channel是用於區分目前調用的是哪個渠道,debugMode是用於區分偵錯模式還是正式模式(一般SDK都會有兩種模式),這裡的debugMode我也用來作為顯示日誌的開關。剩下的key就要根據不同SDK所需要的不同的參數來傳入。
public static void uaLogin(String jsonString)
一般SDK不用傳入jsonString,直接傳一個空的json字串“{}”即可,當有些SDK需要在Login功能中加上切換帳號功能是,我會傳一個type進來,用來判斷此時的操作是登入還是切換帳號。
public static void uaLogout()
用於帳號的退出,這個介面不需要參數。
public static void uaExit()
用於離開遊戲,一般SDK會有一個彈出框來顯示一些論壇或者相關的廣告資訊,這個介面也不需要參數。
public static void uaUpUserInfo
用於資訊的打點,就是報備一些資訊,例如建立角色、角色升級、退出等等。
public static void uaLifeCycle
用於生命週期函數的調用。
public static void uaPay
用於支付。
四、後續思考
最初寫這個架構的時候,大概花費了2天的時間,後續接入中遇到了一些問題,也對這個中介軟體進行了一些修改,總的來說,能夠滿足基本上市面上大部分sdk的接入(至少我現在沒有遇到接入不了的)。重構之後更加的簡潔了,刪掉了不少無用的東西。
但是對於需要監聽onNewIntent等函數的SDK,雖然可以處理(建立一個Activity去處理),卻不太滿意。在思考是否做成一個Activity形式的中介軟體更好(而不是一個Java的class),當然,還有生命週期上的處理,感覺很多東西都有最佳化的空間。
花了整整一天寫的東西,也希望“爬蟲們”在轉寄的同時,也留個原文連結,因為不僅僅是我想把我擁有的知識去分享給他人,我也希望從他人的到寶貴的意見,指出我的錯誤和不足,這才是我寫這篇文章的用意,是作為一個程式員最珍貴的東西,在此謝謝。
源碼地址:
https://github.com/yang8456211/UASDKInter
楊光(atany)原創,轉載請註明博主與博文連結,未經博主允許,禁止任何商業用途。
博文地址:http://blog.csdn.net/yang8456211/article/details/52231305
部落格地址:http://blog.csdn.net/yang8456211
本文遵循“署名-非商業用途-保持一致”創作公用協議
Unity3d Android SDK接入解析(四)通用的Android SDK接入中介軟體