對於cocos2d-x開發者而言,遊戲對多平臺的支持是一個剛需,通常而言須要支持Android和iOS。然而,在開發過程當中,android 平臺遇到的一系列問題着實讓人頭疼,本文以集成新浪微博分享SDK爲例,從3個方面講解Cocos2d-x在Android平臺開發遇到的問題和解決方 法。java
ps. 若是你是新手,請先閱讀Cocos2d-x的Android環境搭建android
目前微博SDK爲開發者提供 Oauth2.0 Web 受權認證,並集成 SSO 登陸功能。你能夠在這裏下載android版本的SDK:https://github.com/sinaweibosdk/weibo_android_sdkc++
在 'readme.md' 中,能夠看到普通JAVA應用程序的集成方式,因此,Oauth2.0和如何申請AppKey等問題,咱們就再也不囉嗦。可是對於Cocos2d-x遊戲而 言,坑爹的問題就出現了:SDK是用Java實現,那咱們怎樣在C++程序中調用Java接口呢?git
接下來主角就出現了:JNIgithub
JNI是JVM實現中的一部分,所以Native語言和Java代碼都運行在JVM的宿主環境。JNI的出現使得開發者既能夠利用Java語言跨平臺、類庫豐 富、開發便捷等特色,又能夠利用Native語言的高效。web
JNI是一個雙向的接口:開發者不只能夠經過JNI在Java代碼中訪問Native模塊,還能夠在 Native代碼中嵌入一個JVM,並經過JNI訪問運行於其中的Java模塊。可見,JNI擔任了一個橋樑的角色,它將JVM與Native模塊聯繫起 來,從而實現了Java代碼與Native代碼的互訪。安全
以下圖:函數
缺點:因爲Native模塊的使用,Java代碼會喪失其原有的跨平臺性和類型安全等特性。可是這不是咱們應該擔憂的,不是嗎?哈哈url
也就是說,JNI是幫助遊戲在Java代碼中調用Native接口和在Native代碼中調用Java接口。spa
通常來講,要在Native代碼中訪問Java對象,有以下幾個步驟:
獲得該Java對象的類定義。JNI定義了jclass 這個類型來表示Java的類的定義,並提供了FindClass接口,根據類的完整的包路徑便可獲得其jclass 。
根據jclass 建立相應的對象實體,即jobject 。在Java中,建立一個新對象只須要使用new 關鍵字便可,但在Native代碼中建立一個對象則須要兩步:首先經過JNI接口GetMethodID獲得該類的構造函數,而後利用NewObject 接口構造出該類的一個實例對象。
訪問jobject 中的成員變量或方法。訪問對象的方法是先獲得方法的Method ID,而後使用CallMethod 接口調用,這裏Type對應相應方法的返回值——返回值爲基本類型的都有相對應的接口,如CallIntMethod;其餘的返回值(包括String) 則爲CallObjectMethod。能夠看出,建立對象實質上是調用對象的一個特殊方法,即構造函數。訪問成員變量的步驟同樣:首先 GetFieldID獲得成員變量的ID,而後Get/SetField讀/寫變量值。
因此,Native端的登錄接口實現以下:
int WebAbility_WeiboLogin(const char *clientID, const char *redirector) { *pEnv = getVMEnvironment(); jclass JavaClass; JavaClass = (*pEnv)->FindClass(pEnv,"com/Tyran/weiboSDK"); jmethodID methId = getMethodID(pEnv,JavaClass,"WeiboLogin", JNI_TRUE); jstring idStr = (*pEnv)->NewString(pEnv,clientID, getUcsLen(clientID)); jstring redirectorStr = (*pEnv)->NewString(pEnv,redirector, getUcsLen(redirector)); (*pEnv)->CallStaticVoidMethod(JavaClass, methId,idStr,redirectorStr); return JNI_TRUE; }
要注意的地方:
FindClass要寫明Java類的完整包路徑,並將 「.」以「/」替換;
GetMethodID的第三個參數是方法名(對於構造函數一概用「」表示),第四個參數是方法的「籤 名」,須要用一個字符串序列表示方法的參數(依聲明順序)和返回值信息。
一樣的,咱們須要在java端建立一個登錄接口,用於調用驗證框的webview:
public static void WeiboLogin(String clientID, String redirector) { Url = HEAD_URL + CLIENT_ID + clientID + RESPONSE_TYPE + REDIRECT_URI + redirector; redirectorStr = redirector; Intent i = new Intent(LaunchActivity.getInstance(), WebViewActivity.class); LaunchActivity.getInstance().startActivity(i); }
這樣,再繼續實現webview相關接口,咱們就可以調用微博的相關功能了,實現代碼會開源出來,這裏就不一一貼出來了。
以上是實現jni的基本方法,看起來很複雜,不是嗎?因此Cocos2d-x對jni進一步封裝了一次,能夠實現更簡單的調用方式。
2dx裏面爲咱們提供了一個JniHelper類,來知足與Java層的數據交互,JniHelper能夠很方便的調用java層的動靜態方法。
再使用JniMethodInfo的env調用執行Java的靜態方法
getStaticMethodInfo,獲取須要調用的java方法信息
getStaticMethodInfo、getMethodInfo
getStaticMethodInfo調用Java靜態方法的方法:
getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode)
第一個參數爲JniMethodInfo,爲一個容器類,表示當前調用的方法
第二個參數爲調用Java方法類的全名
第三個參數爲調用java的方法名,也就是參數爲方法的參數類型
java與Jni對應的參數類型以下:
ava類型 | 對應的簽名 |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | J |
float | F |
double | D |
void | V |
Object | Ljava/lang/String |
Array | Ljava/lang/String |
第四個參數爲返回類型
getMethodInfo相似與第一個函數,只是對應非靜態函數;此函數主要用於獲取Java定義的類非靜態函數是否存在,返回bool;
此類型主要用戶保存類結構體,能夠經過JniHelper類的getStaticMethodInfo函數實例化JniMethodInfo對象, 從而使用實例的env屬性調用CallStaticVoidMethod,CallVoidMethod,CallStaticIntMethod等函數 進行對保存的類結構調用函數;
JniMethodInfo t; bool isHave = JniHelper::getStaticMethodInfo(t, "com/weibo/test/WeiboHelper", //須要調用的Java文件 "toast",//調用的方法名 "()V");//參數
工程中,咱們簡單複用新浪微博demo中的java代碼,因此,彈出的webview效果以下:
雖然Jni在cocos2d-x android工程中的運用很普遍,可是Android項目中,Activity主線程跟c++層是不一樣的,二者分屬不一樣線程,也就是說,Android 的UI線程並不安全,經過Jni直接調用java層方法來作刷新界面等操做是極度危險的。因此在集成一些第三方支付SDK的時候應該很是當心。