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

参数类型 参数简写
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

时间: 2024-10-24 14:54:27

cocos2d 中使用jni C++ 调用 Java 方法的相关文章

cocos2d-x中使用JNI的调用JAVA方法

用cocos2d-x公布Android项目时.都应该知道要用JAVA与C/C++进行交互时会涉及到JNI的操作(Java Native Interface).JNI是JAVA的一个通用接口.旨在本地化语言(如C\C++)与JAVA语言进行交互.在交互过程成中,JAVA调用的是已编译好的本地化语言的二进制代码(如Windows下的dll.Linux下的so文件).所以在交叉编译时看到Eclipse的控制台输出 [armeabi] SharedLibrary  : libcocos2dcpp.so

Android JNI之调用JAVA方法的返回值签名

从http://blog.csdn.net/lonelyroamer/article/details/7932787截取的 如何签名: 下面看看Sign签名如何写,来表示要取得的属性或方法的类型. 1.普通类型签名 2.引用类型签名 object     L开头,然后以/ 分隔包的完整类型,后面再加:   比如说String    签名就是   Ljava/lang/String; Array      以[ 开头,在加上数组元素类型的签名            比如int[]   签名就是[I

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

1.首先是LoadLibrary cocos2d中的C++代码会编译成一个.so文件,放在安卓目录下的libs/armeabi 下,然后java会load进来,这步我们不用做了,因为cocos2d已经帮我们做好了. package cb.CbCCBLE; public class CbCCBLECentralManager { public static final String TAG = "CbCCBLECentralManager Android"; public native

java native interface JNI 调用Java方法

在上一篇文章中介绍了JNI,以及java调用JNI,这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数.JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数. 下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数.每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对

Android Studio NDK开发-JNI调用Java方法

相对于NDK来说SDK里面有更多API可以调用,有时候我们在做NDK开发的时候,需要在JNI直接Java中的方法和变量,比如callback,系统信息等.... 如何在JNI中调用Java方法呢?就需要先了解FindClass和GetMethodID了. FindClass和GetMethodID 在JNI中可以通过FindClass可以找到Java类,得到jclass,例如: jclass clz=(*env)->FindClass(env,"com/jjz/JniHandle"

C通过JNI反向调用JAVA程序方法

JNI反向调用JAVA程序 引述:上文讲过java线程---OS线程的关系,然后C怎样反向调用JAVA程序方法是我们这篇讲的重点 1.ThreadTest中添加run()方法 2.编译ThreadTest.java         javac ThreadTest.java    生成ThreadTest.class 3.javah ThreadTest    生成 ThreadTest.h文件 4.编写ThreadNew.c文件 #include<pthread.h>#include<

C#调用Java方法

C#调用Java方法(详细实例) 阅读目录 C#调用c++ C#调用JAVA方法 C#可以直接引用C++的DLL和转换JAVA写好的程序.最近由于工作原因接触这方面比较多,根据实际需求,我们通过一个具体例子把一个JAVA方法转换成可以由C#直接调用的DLL 回到目录 C#调用c++ C#调用C++的例子网上很多,以一个C++的具体方法为例. C++代码 // 获取一帧图像数据 MVSMARTCAMCTRL_API int __stdcall MV_SC_GetOneFrame(IN void*

C#调用Java方法(详细实例)

C#调用c++ C#调用C++的例子网上很多,以一个C++的具体方法为例. C++代码 // 获取一帧图像数据MVSMARTCAMCTRL_API int __stdcall MV_SC_GetOneFrame(IN void* handle,                                                    IN OUT unsigned char *pData ,                                               

C++调用JAVA方法详解

C++调用JAVA方法详解          博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++调用JAVA主要用到了SUN公司的JNI技术, JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.相关资料见http://java.su