cocos2d 中使用jni C++ 调用 Java 方法

来源:互联网 发布:职业调查报告网络调研 编辑:程序博客网 时间:2024/06/06 03:22

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

参数类型参数简写booleanZbyteBcharCshortSintIlongJfloatFdoubleDvoidV

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


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 TypesJava TypevoidvoidjbooleanbooleanjbytebytejcharcharjshortshortjintintjlonglongjfloatfloatjdoubledoublejobjectAll Java objectsjclassjava.lang.Class objectsjstringjava.lang.String objectsjobjectArrayArray of objectsjbooleanArrayArray of booleansjbyteArrayArray of bytesjshortArrayArray of shortsjintArrayArray of integersjlongArrayArray of longsjfloatArrayArray of floatsjdoubleArrayArray 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

3 0
原创粉丝点击