標籤:
1.單一資料型別例子
假設我們Java中有這麼一個open的靜態方法,它沒有參數,有一個int的傳回值。怎麼在C++中調用它呢?
package cb.CbCCBLE;public class CbCCBLECentralManager { public static final String TAG = "CbCCBLECentralManager Android"; public static int open() { Log.d(TAG,"open"); return 1; }}
下面就是下面具體的調用方法,痛點主要就是getStaticMethodInfo方法的傳入參數。 注意到cb/CbCCBLE/CbCCBLECentralManager,就是安卓的具體包名加上class名字,用中間都加‘/‘。"open"就是方法的名字,最後一個是傳入參數和輸出參數,比較完全符合才能找到這個java方法,括弧內是輸入參數,右邊跟著傳回值。
#if defined(ANDROID)#include "platform/android/jni/JniHelper.h"#include <jni.h>int CbCCBLECentralManager::open(){ JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "open", "()I"); if (! isHave) { CCLOG("FAIL: CbCCBLECentralManager - open"); return 0; } int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID); return result;}#endif
參數和傳回值都會用特殊簡寫來代替,不是int,比如I代表int。完整的參數對於如下:
| 參數類型 |
參數簡寫 |
| boolean |
Z |
| byte |
B |
| char |
C |
| short |
S |
| int |
I |
| long |
J |
| float |
F |
| double |
D |
| void |
V |
表格中提到的簡單類型如果是多個的話用比如是:
public class CbCCBLECentralManager { public static final String TAG = "CbCCBLECentralManager Android"; public static int open(int a, int b) { Log.d(TAG,"open"); return 1; }}
C++調用就如下了:
JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "open", "()II");
注意下CallStaticIntMethod,因為我們調用的是靜態返回int的方法,所以用了這個,要根據調用的方法不同而使用不同的東西,具體參考: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp2556
2.看一個字串的例子,字串會有點麻煩:
Java:
public static int scanPeripheralWithName(String name, long duration) { Log.d(TAG,"scanPeripheralWithName name:" + name + " duration:" + duration); return 1; }
C++
int CbCCBLECentralManager::scanPeripheralWithName(std::string name, long duration){ JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "scanPeripheralWithName", "(Ljava/lang/String;J)I"); if (! isHave) { CCLOG("FAIL: CbCCBLECentralManager - scanPeripheralWithName"); return 0; } jstring jname = minfo.env->NewStringUTF(name.c_str()); jlong jDuration = (long)duration; int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID,jname, jDuration); return result;}
string是一個jobject,jobject要加L作為首碼,因為java中的string類完整+包名就是java/lang/String.所以string的完整就是 Ljava/lang/String,因為是jobject,所以用‘;‘作為結束。
要注意的是CallStaticIntMethod的最後2個參數,我們傳進去了一個jstring和一個jlong。什麼是jstring呢?是這樣的:
jni有自己的資料類型,一般是j開頭,用它們作為java 和 c++的中間媒體。
| JNI Types |
Java Type |
| void |
void |
| jboolean |
boolean |
| jbyte |
byte |
| jchar |
char |
| jshort |
short |
| jint |
int |
| jlong |
long |
| jfloat |
float |
| jdouble |
double |
| jobject |
All Java objects |
| jclass |
java.lang.Class objects |
| jstring |
java.lang.String objects |
| jobjectArray |
Array of objects |
| jbooleanArray |
Array of booleans |
| jbyteArray |
Array of bytes |
| jshortArray |
Array of shorts |
| jintArray |
Array of integers |
| jlongArray |
Array of longs |
| jfloatArray |
Array of floats |
| jdoubleArray |
Array of doubles |
3.看一個數組例子
返回字串的例子:
public static String[] getAllPeripherals() { Log.d(TAG,"getAllPeripherals"); String[] resultArray = {"testPeripheral1", "testPeripheral2"}; //just for test return resultArray; }
std::vector<std::string> CbCCBLECentralManager::getAllPeripherals(){ std::vector<std::string> stdResult; JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "getAllPeripherals", "()[Ljava/lang/String;"); if (! isHave) { CCLOG("FAIL: CbCCBLECentralManager - getAllPeripherals"); //return stdResult; return stdResult; } jobjectArray jResult = static_cast<jobjectArray>(minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID)); jsize resultSize = minfo.env->GetArrayLength(jResult); jsize index = 0; while(index < resultSize) { jstring eachElement = (jstring)minfo.env->GetObjectArrayElement(jResult, index); std::string stdString = JniHelper::jstring2string(eachElement); stdResult.push_back(stdString); ++index; } return stdResult;}
數組前面要加上一個‘[‘, 這裡還用了些其他方法,像得到數組長度,根據index得到數組內容。
傳入字串的例子:
public static int scanPeripheralWithServiceUUIDs(String[] serviceUUIDs, long duration) { Log.d(TAG,"scanPeripheralWithServiceUUIDs:" + duration); }
int CbCCBLECentralManager::scanPeripheralWithServiceUUIDs(std::vector<std::string>serviceUUIDs,long duration){ JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "scanPeripheralWithServiceUUIDs", "([Ljava/lang/String;J)I"); if (! isHave) { CCLOG("FAIL: CbCCBLECentralManager - scanPeripheralWithServiceUUIDs"); return 0; } jint size = serviceUUIDs.size(); jclass StringObject = minfo.env->FindClass("java/lang/String"); jobjectArray jServiceUUIDsArray = minfo.env->NewObjectArray( size, StringObject, NULL); jlong jDuration = (long)duration; for(int i = 0; i < serviceUUIDs.size(); i++) { jstring serviceUUID = minfo.env->NewStringUTF(serviceUUIDs[i].c_str()); minfo.env->SetObjectArrayElement(jServiceUUIDsArray, i, serviceUUID); } int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID, jServiceUUIDsArray, jDuration); return result;}
4.看一個自訂class的例子
package OurBLE;public class OurBlePeripheralAdvertisementData{ public String deviceName;public String getDeviceName(){ return deviceName; }}
比如說有這麼一個class作為jni如何傳遞呢?其實跟那個string類似。
public static OurBlePeripheralAdvertisementData getPeripheralAdvertisementData(String peripheralId) { Log.d(TAG,"getPeripheralAdvertisementData"); OurBlePeripheralAdvertisementData result = new OurBlePeripheralAdvertisementData(); result.deviceName = "deviceName1"; return result; }
CbCCBLEPeripheralAdvertisementData CbCCBLECentralManager::getPeripheralAdvertisementData(std::string peripheralId){ CbCCBLEPeripheralAdvertisementData data = CbCCBLEPeripheralAdvertisementData(); JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "getPeripheralAdvertisementData", "(Ljava/lang/String;)LOurBLE/OurBlePeripheralAdvertisementData;"); if (! isHave) { CCLOG("FAIL: CbCCBLECentralManager - getPeripheralAdvertisementData"); return data; } jstring jPeripheralId = minfo.env->NewStringUTF(peripheralId.c_str()); jobject result = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, jPeripheralId); jclass CbCCBLEPeripheralAdvertisementDataClass = minfo.env->FindClass("OurBLE/OurBlePeripheralAdvertisementData"); jmethodID deviceNameMId = minfo.env->GetMethodID(CbCCBLEPeripheralAdvertisementDataClass, "getDeviceName", "()Ljava/lang/String;"); jstring jDeviceName = (jstring)minfo.env->CallObjectMethod(result, deviceNameMId); //deviceName data.deviceName = JniHelper::jstring2string(jDeviceName); return data;}
主要這裡還用了些FindClass,GetMethodID, CallObjectMethod API,這樣class就能傳遞了。
jni真的是無所不能啊。 《cocos2d 中使用jni Java 調用 C++ 方法》
http://www.waitingfy.com/archives/1648
cocos2d 中使用jni C++ 調用 Java 方法