C++调用Java(一)

2014-11-24 02:35:58 · 作者: · 浏览: 2

通过JNI获取java虚拟机,再获取当前程序的JNI环境,通过JNI环境获取需要调用的java类信息,再获取需要调用的java类中的函数信息。再通过JNI环境调用,使用类信息、函数信息,调用对应的java函数。
看起来好像有点复杂,but不用担心,cocos2d-x中有一个JniHelper类(头文件的copyright为:cocos2d-x.org,是Google提供的还是cocos2d-x小组自己封装的我就不清楚了),它已经把这些工作封装好了。

JniHelper类的使用

加入如下头文件:

#include "platform/android/jni/JniHelper.h"

需要使用的接口如下:

static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);

实现上我们只需要使用上面这两个接口,就可以获取java类的所有函数信息了。JNI环境的获取、各种错误处理都已经在这两个接口实现中封装好了。
先上代码,再来依次讲解每个参数的意义和使用方法:

    //函数信息结构体
    JniMethodInfo minfo;
    bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/
                                                 "com/omega/MyApp",/*类的路径*/
                                                 "getJavaActivity",/*函数名*/
                                                 "()Ljava/lang/Object;");/*函数类型简写*/
    jobject activityObj;
    if (isHave)
    {
        //CallStaticObjectMethod调用java函数,并把返回值赋值给activityObj
        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
    }

OK,很简单。上面的代码,就是使用JNI在C++中调用java类静态函数的典型使用方法。只有两步:

  • 1. 获取java函数的信息,classid、methodid等等
  • 2. 选择JNIEnv中的接口,进行函数调用

    getStaticMethodInfo参数详解

    两个接口的参数一样,意义也相同,详解如下:
    JniMethodInfo &methodinfo JniMethodInfo对象的引用,函数执行中会把jniEvn、classid、methodid写入到引用中。
    const char *className 类的路径,把类的完整包名写全,用法如以上代码。
    const char *methodName 函数名,函数名写上就行了。

    const char *paramCode 函数类型简写
    这个参数需要单独介绍,它的格式为:(参数)返回类型。
    例如:无参数,void返回类型函数,其简写为 ()V
    java中的类型对应的简写如下:

    参数类型 参数简写
    boolean Z
    byte B
    char C
    short S
    int I
    long J
    float F
    double D
    void V
    Object Ljava/lang/String; L用/分割类的完整路径
    Array [Ljava/lang/String; [签名 [I

    多参数的函数
    如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:
    IIII //4个int型参数的函数
    ILjava/lang/String;I //整形,string类型,整形组合 (int x, String a, int y)

    通过JNIEnv进行函数调用

    JNIEvn有一系列的CallStatic[返回类型]Method、Call[返回类型]Method接口,需要针对不同的函数返回类型选择调用。
    [返回类型]以函数返回类型的不同,对应不同的函数名。
    例如:
    CallStaticVoidMethod ―――void
    CallVoidMethod ―――void
    其对应关系如下:

    函数名 函数返回值类型
    Void void
    Object jobject
    Boolean jboolean
    Byte jbyte
    Char jchar
    Short jshort
    Int jint
    Long jlong
    Float jfloat
    Double jdouble

    参数传递
    调用有参数的java函数时,需要把对应的参数传递进去。需要把参数按顺序加入到classid、methodid后面,并且需要做类型转换。例如:

    jint jX = 10;
    jint jY = 10;
    minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jX, jY);

    参数类型转换关系如下:

    C++类型 JAVA类型
    boolean jboolean
    byte jbyte
    char jchar
    short jshort
    int jint
    long jlong
    float jfloat
    double jdouble
    Object jobject
    Class jclass
    String jstring
    Object[] jobjectArray
    boolean[] jbooleanArray
    byte[] jbyteArray
    char[] jcharArray
    short[] jshortArray
    int[] jintArray
    long[] jlongArray
    float[] jfloatArray
    double[] jdoubleArray

    string类型的转换
    实际上我们最常用的参数类型,主要是内建的数据类型、string字符串类型。数据类型可以直接转为j类型,但是string类型需要做如下处理:

    jstring jmsg = minfo.env->NewStringUTF("http://www.baidu.com");
    minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jmsg);

    非静态函数的调用

    非静态函数的调用与静态函数的调用类型,但是需要通过一个静态函数获取java类对象。
    示例:

    //C++代码
        //1. 获取activity静态对象
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                     "com/omega/MyApp",
                                                     "getJavaActivity",
                                                     "()Ljava/lang/Object;");
        jobject activi