cocos2d-x中使用JNI的调用JAVA方法
2014-05-13 21:43
375 查看
用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
[armeabi] Install : libcocos2dcpp.so => libs/armeabi/libcocos2dcpp.so
时即可认为cocos2d-x项目在Android平台编译成功,其原理就是生成这个二进制文件(动态连接库)与Android的本地语言———JAVA进行交互,而交互的过程需要一个中间的桥梁,这个桥梁就是JNI。
那么接下来就记录下如何在cocos2d-x中用C++中使用JNI调用Java语言的中的成员方法或静态方法。
在cocos2d-x中有个已封装好的用于方便操作操作JNI的类——JniHelper,主要通过以下两个函数来获取JAVA类的信息。
methodinfo:JniMethodInfo类的引用
className:类的路径(即包名加类名)
methodName:方法名
paramCode:方法的参数类型和返回值类型
其中的第四个参数的编写规则大致如下:
(参数类型...)返回值类型。
编写规则可以参照oracle的官方文档 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
在c++数据类型映射到java数据类型时已以下的一个联合体方式来定义
可以看到,这个union包含了映射JAVA的8个原声数据类型和一个自定义类型,这样就囊括了JAVA所有的数据类型的映射。
而且,JAVA VM(JAVA虚拟机)还定义了一下的签名来表明JAVA的数据类型
Z boolean
B byte
C char
S shot
I int
J long
F float
D double
L fully-qualified-class; fully-qualified-class(注意分号)
[type type[]
(arg-types)ret-type method type
举个例子来说
如果想调用一下的一个JAVA方法
long f(int n, String s, int[] arr);
那么第四个参数(paramCode)可以写为
(ILjava/lang/String;[I)J
当然,上面的命名规则也可以通过JAVA反编译来获取。
从上图就可以看出一个类的所有方法签名,由此也解释了JAVA虚拟机在解析JAVA字节码时就是通过上面的方法签名来找到相应的方法入口地址。
接下来来测试通过JniHelper来帮助实现c++调用一个带有参数和返回值的静态JAVA方法的过程
1. 创建一个新的cocos2d-x项目,然后拿到Eclipse上去编译。编译完成后编辑入口类,加入我们要测试的JAVA代码
2. 修改HelloWorldScene.cpp,加入jni的调用代码
运行结果就可以看到调用成功:
[armeabi] SharedLibrary : libcocos2dcpp.so
[armeabi] Install : libcocos2dcpp.so => libs/armeabi/libcocos2dcpp.so
时即可认为cocos2d-x项目在Android平台编译成功,其原理就是生成这个二进制文件(动态连接库)与Android的本地语言———JAVA进行交互,而交互的过程需要一个中间的桥梁,这个桥梁就是JNI。
那么接下来就记录下如何在cocos2d-x中用C++中使用JNI调用Java语言的中的成员方法或静态方法。
在cocos2d-x中有个已封装好的用于方便操作操作JNI的类——JniHelper,主要通过以下两个函数来获取JAVA类的信息。
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);顾名思义,第一个函数是获取静态方法的信息,第二个是获取成员方法的信息。其参数都是一致的分别是
methodinfo:JniMethodInfo类的引用
className:类的路径(即包名加类名)
methodName:方法名
paramCode:方法的参数类型和返回值类型
其中的第四个参数的编写规则大致如下:
(参数类型...)返回值类型。
编写规则可以参照oracle的官方文档 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
在c++数据类型映射到java数据类型时已以下的一个联合体方式来定义
typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue;
可以看到,这个union包含了映射JAVA的8个原声数据类型和一个自定义类型,这样就囊括了JAVA所有的数据类型的映射。
而且,JAVA VM(JAVA虚拟机)还定义了一下的签名来表明JAVA的数据类型
Z boolean
B byte
C char
S shot
I int
J long
F float
D double
L fully-qualified-class; fully-qualified-class(注意分号)
[type type[]
(arg-types)ret-type method type
举个例子来说
如果想调用一下的一个JAVA方法
long f(int n, String s, int[] arr);
那么第四个参数(paramCode)可以写为
(ILjava/lang/String;[I)J
当然,上面的命名规则也可以通过JAVA反编译来获取。
从上图就可以看出一个类的所有方法签名,由此也解释了JAVA虚拟机在解析JAVA字节码时就是通过上面的方法签名来找到相应的方法入口地址。
接下来来测试通过JniHelper来帮助实现c++调用一个带有参数和返回值的静态JAVA方法的过程
1. 创建一个新的cocos2d-x项目,然后拿到Eclipse上去编译。编译完成后编辑入口类,加入我们要测试的JAVA代码
package com.cocos2dx.TestJNI; import org.cocos2dx.lib.Cocos2dxActivity; import org.cocos2dx.lib.Cocos2dxGLSurfaceView; import android.os.Bundle; public class TestJNI extends Cocos2dxActivity{ protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); } public Cocos2dxGLSurfaceView onCreateView() { Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this); // TestJNI should create stencil buffer glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8); return glSurfaceView; } static { System.loadLibrary("cocos2dcpp"); } /////////////////////////加入JAVA测试代码///////////////////////// public static String staticMethod(int i, String str, double d) { return "i: " + i + ", str: " + str + ", d: " + d; } }
2. 修改HelloWorldScene.cpp,加入jni的调用代码
#include "HelloWorldScene.h" #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include <jni.h> #include "platform/android/jni/JniHelper.h" #endif USING_NS_CC; CCScene* HelloWorld::scene() { CCScene *scene = CCScene::create(); HelloWorld *layer = HelloWorld::create(); scene->addChild(layer); return scene; } bool HelloWorld::init() { if (!CCLayer::init()) { return false; } #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo methodInfo; //判断方法是否存在 bool isExist = JniHelper::getStaticMethodInfo(methodInfo, "com/cocos2dx/TestJNI/TestJNI", "staticMethod", "(ILjava/lang/String;D)Ljava/lang/String;"); if(isExist) { jint i = 0; jdouble d = 1.22; jstring str = methodInfo.env->NewStringUTF("Test Static Method");//创建 jstring s = (jstring)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, i, str, d);//调用Java方法 const char* c = methodInfo.env->GetStringUTFChars(s, 0);//将jstring转成字符指针 //把返回的字符串显示在屏幕中 CCLabelTTF* ttf = CCLabelTTF::create(c, "Arial", 30); ttf->setPosition(ccp(300, 160)); this->addChild(ttf); //释放内存 methodInfo.env->ReleaseStringUTFChars(s, c); methodInfo.env->DeleteLocalRef(str); }else { CCLog("share error"); } #endif return true; }
运行结果就可以看到调用成功:
相关文章推荐
- cocos2d-x使用jni java调用c++方法(java 调 c++)
- cocos2d 中使用jni Java 调用 C++ 方法
- cocos2d 中使用jni Java 调用 C++ 方法
- cocos2d-x中使用JNI的调用JAVA方法
- cocos2d 中使用jni C++ 调用 Java 方法
- 使用jni实现在C语言中调用Java的方法
- cocos2d-js如何在android平台上使用js直接调用Java方法
- cocos2d-js如何在android平台上使用js直接调用Java方法
- 入门: 使用JNI 从C++代码中调用Java的静态方法
- 【cocos2d-js官方文档】二十四、如何在android平台上使用js直接调用Java方法
- Java-----使用JNI调用本地方法
- 安卓应用开发通过java调用c++ jni的图文使用方法
- 简单的使用jni调用java方法
- 简单的使用jni调用java方法
- 关于JNI的使用(实战linux平台下java调用本地c语言方法)
- JNI进阶一 (C++调用java属性和方法,javap的使用)
- Java使用JNI调用C/C++方法
- 简单的使用jni调用java方法
- 【cocos2d-js官方文档】二十四、如何在android平台上使用js直接调用Java方法
- Android jni 使用C语言调用java中的log方法