1 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
3 | #include "platform/android/jni/JniHelper.h" |
接着通过一小段代码来说明一下这个类的用法。
1 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
12 | bool ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func1" , "()V" ); |
15 | log ( "call void func1() succeed" ); |
17 | info.env->CallStaticVoidMethod(info.classID,info.methodID); |
大家书写代码的时候同样需要将代码使用条件编译写到里面,JniMethodInfo是一个结构体,这个结构体的定义就是代码中注释掉的地方,然后使用JniHelper调用了静态函数getStaticMethodInfo,从它的名字就知道这个函数的作用了,就是获得java层中静态函数的信息,这个信息保存在什么地方呢,当然是JniMethodInfo中了,我们要获取哪个类的哪个函数呢,第二个参数和第三个参数就是告诉JniHelper我们要获取的是哪个函数的信息了,第二个参数是类文件的包名路径,我在org/cocos2dx/cpp这个路径下新建了一个类,叫做TestJni。其实前面的路径就是一个包名,这里使用的时候用/代替.。org的路径当然就是我新建的这个工程的Android平台目录了。一会我要将这个项目打包然后测试一下,在eclipse下看看输出。第三个参数当然就是方法名字了,第四个参数是需要注意的一个,有人把它叫做签名,其实就是你要调用的java层函数的返回值和参数的类型说明。它把调用函数的参数写到前面的括号中,返回值跟在括号的后边,和我们平时书写函数的时候正好相反了。那那个V是什么东西呢,这个大写字母就是对应的一个类型,如果是void类型,那么就用一个V来代替,如果是一个int类型,那么就用一个I代替,是不是很简单,那其他的类型呢,如图所示。
放了俩张表,用得时候查就好了,关于这个参数其他的细节问题待会讨论。整个函数的返回值是一个bool类型,什么意思不用说了吧。当这个函数的信息存在的时候我们就进入到了if中了,然后我使用了info结构体的第一个变量来调用了函数CallStaticVoidMethod,这个函数可真是需要说一说。首先它的调用者就是保存函数信息的结构体JniMethodInfo的第一个成员变量env,这货是什么东西不用管,用就好了。然后这个函数的第一个字母是大写,这一点要小心,Call后边如果跟Static代表的就是我要调用的是一个静态的函数,如果没有那就不是静态的,不是静态的函数,我们使用JniHelper获取信息的时候用得就是getMethodInfo这个函数。然后Void代表的是函数的返回值,来看我们的例子,我调用的函数func1是一个无参无返回值的函数,这个看什么地方,当然java代码我接着会向你展示,但是你可以直接看getStaticMethodInfo这个函数的第四个参数啊。这里的这个void代表的是函数的返回值类型,所以如果调用的是返回值为int的java函数,那就是CallStaticIntMethod了。里边的参数就是结构体info的第二个和第三个成员变量了,代表的是类ID和函数ID。这样的话基本的用法就说清楚了,接着就是TestJni中得代码了,我把要调用到得函数都写了出来。
1 | package org.cocos2dx.cpp; |
3 | import android.util.Log; |
7 | public static void func1() |
9 | Log.e( "xiaota" , "java:func1,called succeed!" ); |
11 | public static int func2() |
15 | public static String func3( int i) |
17 | String str = "get int value:" +i; |
21 | public static String func4(String str) |
26 | public static int func5( int a, int b) |
29 | Log.e( "xiaota" , "func5" ); |
然后打包到Android平台,我们使用USB连接上电脑,打开eclipse,进行调试,看看信息输出了没有。
好了,这样的话就把这个流程都说明白了,下面我们看一些细节的地方。
1 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
3 | log ( "android platform!" ); |
14 | bool ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func1" , "()V" ); |
17 | log ( "call void func1() succeed" ); |
19 | info.env->CallStaticVoidMethod(info.classID,info.methodID); |
23 | ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func2" , "()I" ); |
26 | log ( "call int func2() succeed" ); |
28 | jint iret = info.env->CallStaticIntMethod(info.classID,info.methodID); |
29 | log ( "func2的返回值是%d" ,iret); |
33 | ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func3" , "(I)Ljava/lang/String;" ); |
36 | log ( "call int func3(int) succeed" ); |
38 | jobject jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID,1438); |
42 | ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func4" , "(Ljava/lang/String;)Ljava/lang/String;" ); |
45 | log ( "call string func4(string) succeed" ); |
46 | jobject para = info.env->NewStringUTF( "haha" ); |
47 | jstring jstr = (jstring)info.env->CallStaticObjectMethod(info.classID,info.methodID,para); |
49 | std::string text = JniHelper::jstring2string(jstr); |
50 | log ( "%s" ,text.c_str()); |
54 | ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func5" , "(II)I" ); |
57 | log ( "call int func5(int a,int b) succeed" ); |
58 | jint iret = info.env->CallStaticIntMethod(info.classID,info.methodID,1,2); |
59 | log ( "return value is %d" ,iret); |
上边的代码主要还是那俩个函数调用的说明,getStaticMethodInfo的第四个参数如果是类类型,注意要使用的签名,后边的分号也要加,如果参数有多个,直接连起来书写就可以了。使用CallStaticMethod调用的时候注意一下参数和返回值的类型,传递参数的时候直接写到函数的后边,但是参数类型要正确,返回值使用对应的类型来接受,这个类型就是前面加一个j,比如java层返回的类型是int,那接受的类型就是jint,java层返回object,接受类型就是jobject。
以上是调用java的静态函数,接下来是非静态函数的调用。我将c++的代码和java的代码都贴出来。
2 | bool ret = JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJniHelper" , "getObj" , "()Ljava/lang/Object;" ); |
7 | log ( "call static method" ); |
8 | jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID); |
11 | bool re = JniHelper::getMethodInfo(info, "org/cocos2dx/cpp/TestJniHelper" , "func" , "()V" ); |
14 | log ( "call no-static method" ); |
16 | info.env->CallVoidMethod(jobj,info.methodID); |
1 | package org.cocos2dx.cpp; |
3 | import android.util.Log; |
5 | public class TestJniHelper |
7 | private static TestJniHelper instance = new TestJniHelper(); |
8 | public static Object getObj() |
14 | Log.e( "xiaota" , "func is called" ); |
因为调用的是非静态的函数,所以我们使用CallVoidMethod的时候就不能传入类ID了,要传入一个对象,告诉它调用的是哪个对象的方法,所以为了有这么一个对象,我们就得先调用一个静态的方法来返回这个对象,然后用这个对象作为参数调用非静态函数。好了,关于Jni的基本用法就是这样了,只是本人的一点拙见,没有了解过的可以看看,如果是大神就绕路吧。