經過JNI獲取java虛擬機,再獲取當前程序的JNI環境,經過JNI環境獲取須要調用的java類信息,再獲取須要調用的java類中的函數信息。再經過JNI環境調用,使用類信息、函數信息,調用對應的java函數。
看起來好像有點複雜,but不用擔憂,cocos2d-x中有一個JniHelper類(頭文件的copyright爲:cocos2d-x.org,是Google提供的仍是cocos2d-x小組本身封裝的我就不清楚了),它已經把這些工做封裝好了。java
加入以下頭文件:android
#include "platform/android/jni/JniHelper.h"
須要使用的接口以下:c++
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode); static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
實現上咱們只須要使用上面這兩個接口,就能夠獲取java類的全部函數信息了。JNI環境的獲取、各類錯誤處理都已經在這兩個接口實現中封裝好了。
先上代碼,再來依次講解每一個參數的意義和使用方法:web
//函數信息結構體 JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/ "com/omega/MyApp",/*類的路徑*/ "getJavaActivity",/*函數名*/ "()Ljava/lang/Object;");/*函數類型簡寫*/ jobject activityObj; if (isHave) { //CallStaticObjectMethod調用java函數,並把返回值賦值給activityObj activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); }
OK,很簡單。上面的代碼,就是使用JNI在C++中調用java類靜態函數的典型使用方法。只有兩步:數組
兩個接口的參數同樣,意義也相同,詳解以下:
JniMethodInfo &methodinfo JniMethodInfo對象的引用,函數執行中會把jniEvn、classid、methodid寫入到引用中。
const char *className 類的路徑,把類的完整包名寫全,用法如以上代碼。
const char *methodName 函數名,函數名寫上就好了。ide
const char *paramCode 函數類型簡寫
這個參數須要單獨介紹,它的格式爲:(參數)返回類型。
例如:無參數,void返回類型函數,其簡寫爲 ()V
java中的類型對應的簡寫以下:函數
參數類型 | 參數簡寫 |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | J |
float | F |
double | D |
void | V |
Object | Ljava/lang/String; L用/分割類的完整路徑 |
Array | [Ljava/lang/String; [簽名 [I |
多參數的函數
若是函數有多個參數,直接把簡寫並列便可。注意Object與Array型參數簡寫結尾的分號,示例:
IIII //4個int型參數的函數
ILjava/lang/String;I //整形,string類型,整形組合 (int x, String a, int y)測試
JNIEvn有一系列的CallStatic[返回類型]Method、Call[返回類型]Method接口,須要針對不一樣的函數返回類型選擇調用。
[返回類型]以函數返回類型的不一樣,對應不一樣的函數名。
例如:
CallStaticVoidMethod ———void
CallVoidMethod ———void
其對應關係以下:this
函數名 | 函數返回值類型 |
---|---|
Void | void |
Object | jobject |
Boolean | jboolean |
Byte | jbyte |
Char | jchar |
Short | jshort |
Int | jint |
Long | jlong |
Float | jfloat |
Double | jdouble |
參數傳遞
調用有參數的java函數時,須要把對應的參數傳遞進去。須要把參數按順序加入到classid、methodid後面,而且須要作類型轉換。例如:.net
jint jX = 10; jint jY = 10; minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jX, jY);
參數類型轉換關係以下:
C++類型 | JAVA類型 |
---|---|
boolean | jboolean |
byte | jbyte |
char | jchar |
short | jshort |
int | jint |
long | jlong |
float | jfloat |
double | jdouble |
Object | jobject |
Class | jclass |
String | jstring |
Object[] | jobjectArray |
boolean[] | jbooleanArray |
byte[] | jbyteArray |
char[] | jcharArray |
short[] | jshortArray |
int[] | jintArray |
long[] | jlongArray |
float[] | jfloatArray |
double[] | jdoubleArray |
string類型的轉換
實際上咱們最經常使用的參數類型,主要是內建的數據類型、string字符串類型。數據類型能夠直接轉爲j類型,可是string類型須要作以下處理:
jstring jmsg = minfo.env->NewStringUTF("http://www.baidu.com"); minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jmsg);
非靜態函數的調用與靜態函數的調用類型,可是須要經過一個靜態函數獲取java類對象。
示例:
//C++代碼 //1. 獲取activity靜態對象 JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/omega/MyApp", "getJavaActivity", "()Ljava/lang/Object;"); jobject activityObj; if (isHave) { //調用靜態函數getJavaActivity,獲取java類對象。 activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); } //2. 查找displayWebView接口,獲取其函數信息,並用jobj調用 isHave = JniHelper::getMethodInfo(minfo,"com/omega/MyApp","displayWebView", "(IIII)V"); if (!isHave) { CCLog("jni:displayWebView 函數不存在"); } else { //調用此函數 jint jX = (int)tlX; jint jY = (int)tlY; jint jWidth = (int)webWidth; jint jHeight = (int)webHeight; //調用displayWebView函數,並傳入參數 minfo.env->CallVoidMethod(activityObj, minfo.methodID, jX, jY, jWidth, jHeight); }
最後,放一塊比較詳細的JNI使用代碼,基本上覆蓋了的所有使用狀況。
JniMethodInfo minfo;//JniHelper /* 測試用方法 */ /*bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","loginGree", "()V"); // if (isHave) { //CCLog("有showText "); minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID); }else { //CCLog("沒有方法showText"); }*/ /* 分享 */ /*//將c++中的string轉換成java中的string //char str[] = "test"; bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","shareSina", "(Ljava/lang/String;Ljava/lang/String;)V"); // if (isHave) { //CCLog("有share "); jstring jstr = minfo.env->NewStringUTF("test1 share"); jstring jst = minfo.env->NewStringUTF("/data/data/com.cocoa/cy.png"); //jstring jst = minfo.env->NewStringUTF(""); minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,jstr,jst); }else { //CCLog("沒有方法share"); }*/ /* 設置高分 */ /*jint ind = 0; jlong lsre = 2202l; bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","setHighScore", "(IJ)V"); if (isHave) { minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,ind,lsre); }*/ /* 成就解鎖 */ /*jint aind = 0; bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","unLock", "(I)V"); if (isHave) { minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,aind); }*/ /* 測試用方法 */ bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","rtnActivity","()Ljava/lang/Object;"); jobject jobj; if (isHave) { jobj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); } //CCLog(" jobj存在"); /* 測試用方法,非靜態無參數無返回值方法 */ /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "()V"); if (isHave) { minfo.env -> CallVoidMethod(jobj,minfo.methodID); }*/ /* 測試用方法,非靜態有java類型的String參數無返回值方法 */ /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;)V"); if (isHave) { jstring jmsg = minfo.env->NewStringUTF("msg okey!"); minfo.env -> CallVoidMethod(jobj,minfo.methodID,jmsg); }*/ /* 測試用方法,返回java類型的String,有java類型的String和int參數方法 */ /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;I)Ljava/lang/String;"); if (isHave) { jstring jmsg = minfo.env->NewStringUTF("msg okey! return string"); jint index = 0; minfo.env -> CallObjectMethod(jobj,minfo.methodID,jmsg,index); }*/ /* 測試用方法,返回java類型的String[],有java類型的String[]和int參數方法 */ /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "([Ljava/lang/String;I)[Ljava/lang/String;"); if (isHave) { jobjectArray args = 0; jstring str; jsize len = 5; const char* sa[] = {"Hi,","World!","JNI ","is ","fun"}; int i = 0; args = minfo.env->NewObjectArray(len,minfo.env->FindClass("java/lang/String"),0); for(i=0;iNewStringUTF(sa[i]); minfo.env->SetObjectArrayElement(args,i,str); } //minfo.env->GetStringArrayRegion(args,0,10,buf); //jintArray jmsg = {1,2,3}; //minfo.env->NewStringUTF("msg okey! return string"); jint index = 0; minfo.env -> CallObjectMethod(jobj,minfo.methodID,args,index); }*/ /* 測試用方法,無返回類型,有java類型的int[]和int參數方法 */ /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([II)V"); if (isHave) { jint buf[]={7,5,8,9,3}; jintArray jintArr; //定義jint數組 jintArr = minfo.env->NewIntArray(5); minfo.env->SetIntArrayRegion(jintArr,0,5,buf); jint index = 0; minfo.env -> CallVoidMethod(jobj,minfo.methodID,jintArr,index); }*/ /* 測試用方法,無返回類型,有java類型的byte[]和int參數方法 */ isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([BI)V"); if (isHave) { jbyte buf[]={7,5,8,9,3}; jbyteArray jbyteArr; //定義jbyte數組 jbyteArr = minfo.env->NewByteArray(5); minfo.env->SetByteArrayRegion(jbyteArr,0,5,buf); jint index = 0; minfo.env -> CallVoidMethod(jobj,minfo.methodID,jbyteArr,index); }
private static HiWorld hiWorld = null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); hiWorld = this; if (detectOpenGLES20()) { // get the packageName,it's used to set the resource path String packageName = getApplication().getPackageName(); super.setPackageName(packageName); // set content setContentView(R.layout.game_demo); getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.window_title); mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.game_gl_surfaceview); mGLView.setTextField((Cocos2dxEditText) findViewById(R.id.textField)); mGLView.setEGLContextClientVersion(2); mGLView.setCocos2dxRenderer(new Cocos2dxRenderer()); task = new TimerTask() { @Override public void run() { // HiWorld.shoot(hiWorld); Log.e("-------------------", "-------------------"); // 調用c++中的方法 System.out.println("------------------------" + stringZjy1()); } }; timer = new Timer(); timer.schedule(task, 5000); } else { Log.d("activity", "don't support gles2.0"); finish(); } static { System.loadLibrary("game"); } // c++中調用的方法 public static Object rtnActivity() { System.out.println("----------rtnActivity"); return hiWorld; } // c++中調用的方法,傳String類型 public void showText(final String msg) { // 添加到主線程 hiWorld.runOnUiThread(new Runnable() { public void run() { System.out.println("----------msg:"+msg); } }); } //c++中調用的方法,傳String類型和int類型 public String showText(final String msg,final int index) { // 添加到主線程 hiWorld.runOnUiThread(new Runnable() { public void run() { System.out.println("----------msg:"+msg+"; index="+index); } }); return "okey String showText(final String msg,final int index)"; } //c++中調用的方法,傳String[]類型和int類型 public String[] showText(final String[] msg,final int index) { String[] strArr = {"1","2","3","4","5"}; // 添加到主線程 hiWorld.runOnUiThread(new Runnable() { public void run() { for(String _str:msg){ System.out.println("----------String[] msg:"+_str+"; index="+index); } } }); return strArr; } //c++中調用的方法,傳int[]類型和int類型 public void testArr(final int msg[],final int index) { // 添加到主線程 hiWorld.runOnUiThread(new Runnable() { public void run() { System.out.println("----------int[] msg len:"+msg.length); for(int _bl:msg){ System.out.println("----------int[] msg:"+_bl+"; index="+index); } } }); } //c++中調用的方法,傳int[]類型和int類型 public void testArr(final byte msg[],final int index) { // 添加到主線程 hiWorld.runOnUiThread(new Runnable() { public void run() { System.out.println("----------byte[] msg len:"+msg.length); for(int _bl:msg){ System.out.println("----------byte[] msg:"+_bl+"; index="+index); } } }); }
From:http://blog.csdn.net/luxiaoyu_sdc/article/details/15874505