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

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

charshortintlongfloatdoublevoid
参数类型 参数简写
boolean Z
byte B
C
S
I
J
F
D
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,"()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,"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,"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,"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,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,"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,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

相关文章

操作步骤 1、创建cocos2d-x工程 2、新建 Scene1.cpp Scene1.h Scene1.h代码 #ifndef __SCENE1_H__#defi...
开发环境:OS(WINDOWS 8.1 X64 企业版) cocos2d-x 2.2.1 vs2010 想给vs安装上cocos的模版,执行Install...
把创建项目做成一个批处理,当创建项目时可以省时省力很多。 操作步骤 1、在 E:cocos2d-x-2.2.1toolspr...
https://www.cnblogs.com/JiaoQing/p/3906780.html 四个响应函数 1 EventListenerPhysicsContact* evC...
转载于 http://www.cnblogs.com/kenkofox/p/3926797.html 熟悉js的dom事件或者flash事件的,基本都能立...
ScrollView(滚动容器)加载大量item时会导致游戏界面的卡顿,严重时整个界面会出现卡死的情况。最近项...