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

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。完整的参数对于如下:


1.jpg

表格中提到的简单类型如果是多个的话用比如是:

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++调用就如下了:

1JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "open", "()II");

注意下CallStaticIntMethod,因为我们调用的是静态的返回int的方法,所以用了这个,要根据调用的方法不同而使用不同的东西,具体参考这里。

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++的中间媒体。


2.jpg

3.看一个数组例子

返回字符串的例子:

public static String[] getAllPeripherals()

{

Log.d(TAG,"getAllPeripherals");

String[] resultArray = {"testPeripheral1", "testPeripheral2"}; //just for test

return resultArray;

}

std::vector CbCCBLECentralManager::getAllPeripherals()

{

std::vector 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(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::vectorserviceUUIDs,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)

{

CbCCBLEPeripheralAdvertise mentData 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真的是无所不能啊。Java调用C++参考这篇文章。 《Cocos2d-x 中使用jni Java 调用 C++ 方法》