`
473687880
  • 浏览: 484137 次
文章分类
社区版块
存档分类
最新评论

cocos2d-x 通过JNI实现c/c++和Android的java层函数互调

 
阅读更多
文章摘要:本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。 (2)通过c++函数调用Android的java层函数,显示一个对话框,点击按钮退出程序。 1. 首先来简单学习一下JNI的相关知识,我这篇文章中简单实现了怎么在Android Java层调用c++函数。要想使用JNI,必须得…

本文主要实现两个功能:
(1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。
(2)通过c++函数调用Android的java层函数,显示一个对话框,点击按钮退出程序。

1. 首先来简单学习一下JNI的相关知识,我这篇文章中简单实现了怎么在Android Java层调用c++函数。要想使用JNI,必须得包含头文件,android是使用ndk编译c/c++的,这里jni.h文件位于:\android-ndk-r8b\platforms\android-14\arch-arm\usr\include\jni.h,该文件定义了所有和JNI相关的数据类型和接口。下面是相关代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include <inttypes.h> /* C99 */
typedefuint8_t jboolean; /* unsigned 8 bits */
typedefint8_t jbyte; /* signed 8 bits */
typedefuint16_t jchar; /* unsigned 16 bits */
typedefint16_t jshort; /* signed 16 bits */
typedefint32_t jint; /* signed 32 bits */
typedefint64_t jlong; /* signed 64 bits */
typedeffloatjfloat;/* 32-bit IEEE 754 */
typedefdoublejdouble;/* 64-bit IEEE 754 */
#else
typedefunsignedcharjboolean;/* unsigned 8 bits */
typedefsignedcharjbyte;/* signed 8 bits */
typedefunsignedshortjchar;/* unsigned 16 bits */
typedefshortjshort;/* signed 16 bits */
typedefintjint;/* signed 32 bits */
typedeflonglongjlong;/* signed 64 bits */
typedeffloatjfloat;/* 32-bit IEEE 754 */
typedefdoublejdouble;/* 64-bit IEEE 754 */
#endif
/* "cardinal indices and sizes" */
typedefjint jsize;
#ifdef __cplusplus
/*
* Reference types, in C++
*/
class_jobject {};
class_jclass : public_jobject {};
class_jstring : public_jobject {};
class_jarray : public_jobject {};
class_jobjectArray : public_jarray {};
class_jbooleanArray : public_jarray {};
class_jbyteArray : public_jarray {};
class_jcharArray : public_jarray {};
class_jshortArray : public_jarray {};
class_jintArray : public_jarray {};
class_jlongArray : public_jarray {};
class_jfloatArray : public_jarray {};
class_jdoubleArray : public_jarray {};
class_jthrowable : public_jobject {};
typedef_jobject* jobject;
typedef_jclass* jclass;
typedef_jstring* jstring;
typedef_jarray* jarray;
typedef_jobjectArray* jobjectArray;
typedef_jbooleanArray* jbooleanArray;
typedef_jbyteArray* jbyteArray;
typedef_jcharArray* jcharArray;
typedef_jshortArray* jshortArray;
typedef_jintArray* jintArray;
typedef_jlongArray* jlongArray;
typedef_jfloatArray* jfloatArray;
typedef_jdoubleArray* jdoubleArray;
typedef_jthrowable* jthrowable;
typedef_jobject* jweak;
#else /* not __cplusplus */
/*
* Reference types, in C.
*/
typedefvoid* jobject;
typedefjobject jclass;
typedefjobject jstring;
typedefjobject jarray;
typedefjarray jobjectArray;
typedefjarray jbooleanArray;
typedefjarray jbyteArray;
typedefjarray jcharArray;
typedefjarray jshortArray;
typedefjarray jintArray;
typedefjarray jlongArray;
typedefjarray jfloatArray;
typedefjarray jdoubleArray;
typedefjobject jthrowable;
typedefjobject jweak;
#endif /* not __cplusplus */

我们经常用到的是JNIEnv*,它是一个c结构体,封装了许多常用的函数,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct_JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
conststructJNINativeInterface* functions;
#if defined(__cplusplus)
jint GetVersion()
{returnfunctions->GetVersion(this); }
jclass DefineClass(constchar*name, jobject loader, constjbyte* buf,
jsize bufLen)
{returnfunctions->DefineClass(this, name, loader, buf, bufLen); }
jclass FindClass(constchar* name)
{returnfunctions->FindClass(this, name); }
// 这里省略其他函数...
}

cocos2d-x引擎对jni的操作进行了封装,提供了一个非常好用的类:JniHelper,定义了一些常用的接口,该文件位于cocos2dx/platform/android/jni目录下。下面看看JniHelper.h源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedefstructJniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
classCC_DLL JniHelper
{
public:
staticJavaVM* getJavaVM();
staticvoidsetJavaVM(JavaVM *javaVM);
staticconstchar* getExternalAssetPath();
staticvoidsetExternalAssetPath(constchar* externalAssetPath);
staticjclass getClassID(constchar*className, JNIEnv *env=0);
staticboolgetStaticMethodInfo(JniMethodInfo &methodinfo, constchar*className,constchar*methodName,constchar*paramCode);
staticboolgetMethodInfo(JniMethodInfo &methodinfo, constchar*className,constchar*methodName,constchar*paramCode);
staticstd::string jstring2string(jstring str);
private:
staticJavaVM *m_psJavaVM;
staticstd::string m_externalAssetPath;
};

下面来解释JniHelper的两个常用函数:
(1)getStaticMethodInfo
用来判断Java的类静态函数是否存在,并初始化结构体JniMethodInfo,该结构体封装了JNIEnv*和java.lang.Class对象、函数ID。这样就可以使用JNIEnv*调用 CallStaticXXXMethod(jclass clazz, jmethodID methodID, …)和 CallXXXMethod(jobject obj, jmethodID methodID, …)等常用函数(XXX替换为函数返回值类型,如:Void,Int等)。
第一个参数为JniMethodInfo,第二个参数是类的绝对路径,第三个参数是函数名,第四个参数是函数签名(参数和返回类型),示例代码如下:

1
2
3
4
if(JniHelper::getStaticMethodInfo(t, CLASS_NAME, "showTipDialog","(Ljava/lang/String;Ljava/lang/String;)V"))
{
//...
}

关于类型签名,请对照下图:

(2)getMethodInfo
该函数与getStaticMethodInfo类似,用于Java类的非静态函数。

2. 下面开始实现文章开头所述的两个功能,本文是在cocos2d-x 2.0版本 自适应屏幕分辨率demo的基础上添加的。
(1)利用cocos2d-x创建一个Android工程,名为JniTest,包名为com.alexzhou.jni,此时该包下会自动生成一个JniTest.java文件。
(2)首先来实现把应用程序的包名传递给c++函数,在包下创建JniTestHelper.java,该类封装了给c++调用的函数,添加如下代码:

1
2
3
4
5
6
7
8
privatestaticHandler mHandler;
publicstaticvoidinit(Handler handler)
{
JniTestHelper.mHandler = handler;
}
publicstaticnativevoidsetPackageName(String packageName);

(3)打开JniTest.java,在onCreate函数中添加下面的代码:

1
2
3
4
5
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
JniTestHelper.init(mHandler);
JniTestHelper.setPackageName(this.getPackageName());
}

(4)java层的代码已经完成了,下面来编写jni层代码,在/jni/hellocpp/下创建test.h和test.cpp文件,test.h文件暂时不添加任何函数,代码如下:
test.h

1
2
3
4
#ifndef TEST_H
#define TEST_H
#endif

test.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "cocos2d.h"
#include <jni.h>
#include "platform/android/jni/JniHelper.h"
#include "test.h"
#include "JniTest.h"
#define CLASS_NAME "com/alexzhou/jni/JniTestHelper"
usingnamespacecocos2d;
extern"C"
{
voidJava_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName)
{
constchar*pkgName = env->GetStringUTFChars(packageName, NULL);
setPackageName(pkgName);
env->ReleaseStringUTFChars(packageName, pkgName);
}
}

必须加上extern “C”,声明以c语言的方式进行编译,因为c++和c在编译时生成的函数签名不一样,可以在网上查找相关资料,不然运行的时候会出现链接错误。
(5)现在编写c++函数,在Classes目录下创建JniTest.h,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef JNI_TEST_H
#define JNI_TEST_H
#include "cocos2d.h"
usingnamespacecocos2d;
voidsetPackageName(constchar*packageName)
{
CCLog("packageName: %s", packageName);
}
#endif

(6)修改jni/Android.mk文件的LOCAL_SRC_FILES值 ,内容如下:

1
2
LOCAL_SRC_FILES := hellocpp/main.cpp \
hellocpp/test.cpp

(7)编译运行,因为我是使用cygwin编译的,而且Android项目不在cocos2d-x的根目录下,所以需要修改build_native.sh,修改COCOS2DX_ROOT和NDK_MODULE_PATH的值,把当前cocos2d-x项目的路径添加到NDK_MODULE_PATH,修改后的值:

1
2
3
COCOS2DX_ROOT="/cygdrive/e/cocos2d-x/cocos2d-2.0-x-2.0.4"
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt:${APP_ROOT}"

运行结果:

(8)现在来实现通过c++函数调用java层函数,显示一个对话框。在JniTestHelper.java添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
publicstaticnativevoidexitApp();
privatestaticvoidshowTipDialog(finalString title, finalString text)
{
Message msg = mHandler.obtainMessage();
msg.what = JniTest.SHOW_DIALOG;
DialogMessage dm = newDialogMessage();
dm.title = title;
dm.msg = text;
msg.obj = dm;
msg.sendToTarget();
}

(9)创建一个DialogMessage.java,封装dialog要显示的数据。

1
2
3
4
5
6
7
8
9
10
11
/**
author:alexzhou
email :zhoujiangbohai@163.com
date :2012-12-14
**/
publicclassDialogMessage {
publicString title;
publicString msg;
}

(10) 修改JniTest.java,添加显示对话框的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
publicstaticfinalintSHOW_DIALOG = 0x0001;
privateHandler mHandler = newHandler()
{
@Override
publicvoidhandleMessage(Message msg) {
switch(msg.what)
{
caseSHOW_DIALOG:
DialogMessage dm = (DialogMessage)msg.obj;
newAlertDialog.Builder(JniTest.this)
.setTitle(dm.title)
.setMessage(dm.msg).setNegativeButton("cancle",newDialogInterface.OnClickListener() {
@Override
publicvoidonClick(DialogInterface dialog, intwhich) {
dialog.dismiss();
}
})
.setPositiveButton("Ok",
newDialogInterface.OnClickListener() {
@Override
publicvoidonClick(DialogInterface dialog, intwhich) {
dialog.dismiss();
JniTestHelper.exitApp();
}
})
.create().show();
break;
}
}
};

(11)在test.h和test.cpp中添加显示对话框的接口:
test.h

1
2
3
4
extern"C"
{
voidshowTipDialog(constchar*title,constchar*msg);
}

test.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
extern"C"
{
voidshowTipDialog(constchar*title,constchar*msg)
{
JniMethodInfo t;
if(JniHelper::getStaticMethodInfo(t, CLASS_NAME, "showTipDialog","(Ljava/lang/String;Ljava/lang/String;)V"))
{
jstring jTitle = t.env->NewStringUTF(title);
jstring jMsg = t.env->NewStringUTF(msg);
t.env->CallStaticVoidMethod(t.classID, t.methodID, jTitle, jMsg);
t.env->DeleteLocalRef(jTitle);
t.env->DeleteLocalRef(jMsg);
}
}
voidJava_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName)
{
constchar*pkgName = env->GetStringUTFChars(packageName, NULL);
setPackageName(pkgName);
env->ReleaseStringUTFChars(packageName, pkgName);
}
voidJava_com_alexzhou_jni_JniTestHelper_exitApp(JNIEnv *env, jobject thiz)
{
exitApp();
}
}

(12) 修改Classes目录下的JniTest.h,添加代码:

1
2
3
4
voidexitApp()
{
CCDirector::sharedDirector()->end();
}

(13)到此为止,所有代码都已经完成了,代码比较简单就不详细解释了,现在编译运行,效果如下:

免分源码:http://download.csdn.net/detail/kaitiren/6256205





李华明版本转载“

首先Himi大概的介绍一个类JniHelper ;

此类主要用于Jni与Java层之间的相互访问的作用,那么此类的常用的一些函数这里首先介绍下,否则直接上代码不太容易吸收 ;

JniHelper 类常用函数:

1. getStaticMethodInfo (四个参数,bool 返回值)

使用示例代码:

boolisHave = JniHelper::getStaticMethodInfo(minfo,"com/ai/ommr/OhMonsterMR4Android","testFun","()V");

此函数主要用于获取Java定义的类静态函数是否存在,返回bool;

此函数有3个参数:

第一参数:minfo ->JniMethodInfo 类型,后面详细说;

第二个参数:类的路径。

第三个参数:方法名(第一参数类中的函数)

第四个参数:(参数)返回类型

关于第一个和第二个参数都比较容易理解,那么第三个参数需要重点介绍一下;例如你在Java中定义一个如下函数 public void helloJni(){};

那么getStaticMethodInfo函数第三个参数你应该传入 “()V” 表示此函数无参无返回值!

如果有这么一个函数:public int helloJni(int _int){return 823};

那么getStaticMethodInfo函数第三个参数你应该传入 “(I)I” 表示此函数需要传入一个int类型的参数并且返回一个int类型!

大概说两个童鞋们应该基本理解了,那么下面详细写一些对照表,留给大家对照;

参数、返回值样式对照表:

这里的签名指的就是getStaticMethodInfo函数第三个参数中传入的样式;

2. getMethodInfo 类似与第一个函数,只是对应非静态函数;此函数主要用于获取Java定义的类非静态函数是否存在,返回bool;

JniMethodInfo类:

此类型主要用户保存类结构体,可以通过JniHelper类的getStaticMethodInfo函数实例化JniMethodInfo对象,从而使用实例的env属性调用CallStaticVoidMethod,CallVoidMethod,CallStaticIntMethod等函数进行对保存的类结构调用函数;

常用的函数如下:(静态系列函数)

1. CallStaticVoidMethod(classID,methodID);

2.CallStaticIntMethod(classID,methodID);

3~(n-1) ……省略掉,童鞋们一看就明白;

n.CallStaticObjectMethod(classID,methodID);

带参数的函数:(如int类型)

CallStaticVoidMethod(classID,methodID,int _int);

非静态系列函数:

1. CallVoidMethod(jobj,methodID);

2.CallIntMethod(jobj,methodID);

3~(n-1) ……省略掉,童鞋们一看就明白;

n.CallStaticObjectMethod(jobj,methodID);

带参数的函数:(如int类型)

CallVoidMethod(classID,methodID,int _int);

这里讲解下几个参数函数:

1. classID: 类ID ,JniMethodInfo 对象包含此属性;

2. methdID: 方法ID,JniMethodInfo 对象也包含此属性;

3. jobj : java中Object类型,如自定义类,String…

非静态函数调用的时候,需要的是对象,所以与静态函数调用的第一个参数不同;

那么既然能调用Java的函数,那就能得到函数返回值,但是这里我们得到的返回值书写类型如下:

譬如返回int 类型,在Xcode中使用 jint 这种形式,更多形式如下:

int -> jint

…省略,大家一看就懂得;

object -> jobject

估计有的童鞋已经晕了,没关系,下面Himi写了一些例子代码,结合来看就一目了然啦。

Xcode中先导入如下头文件:

  1. //使用预编译,对当前平台为Android时才会导入如下头文件
  2. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)
  3. #include<jni.h>
  4. #include"platform/android/jni/JniHelper.h"
  5. #include<android/log.h>
  6. #endif

示例代码段1:

Xcode 代码:

  1. ////静态函数示例1.无参数,无返回值---------------------------------$$$$$$-----------------------------
  2. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)//判断当前是否为Android平台
  3. JniMethodInfominfo;//定义Jni函数信息结构体
  4. //getStaticMethodInfo次函数返回一个bool值表示是否找到此函数
  5. boolisHave=JniHelper::getStaticMethodInfo(minfo,"com/ai/ommr/OhMonsterMR4Android","testFun","()V");
  6. if(!isHave){
  7. CCLog("jni:此函数不存在");
  8. }else{
  9. CCLog("jni:此函数存在");
  10. //调用此函数
  11. minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID);
  12. }
  13. CCLog("jni-java函数执行完毕");
  14. #endif
Android(Java) 代码:

  1. //静态函数示例1.无参数,无返回值
  2. publicstaticvoidtestFun(){
  3. Log.e("Himi","静态函数示例1.无参数,无返回值");
  4. }

运行截图:

示例代码段2:

Xcode 代码:

  1. //静态函数示例2.有参数,无返回值------------------------------$$$$$$$--------------------------------
  2. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)//判断当前是否为Android平台
  3. JniMethodInfominfo;//定义Jni函数信息结构体
  4. //getStaticMethodInfo次函数返回一个bool值表示是否找到此函数
  5. boolisHave=JniHelper::getStaticMethodInfo(minfo,
  6. "com/ai/ommr/OhMonsterMR4Android","testFunWithInt","(I)V");
  7. if(!isHave){
  8. CCLog("jni:此函数不存在");
  9. }else{
  10. CCLog("jni:此函数存在");
  11. //调用此函数
  12. minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID,823);
  13. }
  14. CCLog("jni-java函数执行完毕");
  15. #endif

Android(Java) 代码:

  1. //静态函数示例2.有参数,无返回值
  2. publicstaticvoidtestFunWithInt(int_int){
  3. Log.e("Himi","静态函数示例1.有参数,无返回值;传入的参数int="+_int);
  4. }

运行截图:

示例代码段3:

Xcode 代码:

  1. //静态函数示例3.有参数,有返回值--------------------------------$$$$$$$--------------------------------
  2. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)//判断当前是否为Android平台
  3. JniMethodInfominfo;//定义Jni函数信息结构体
  4. //getStaticMethodInfo次函数返回一个bool值表示是否找到此函数
  5. boolisHave=JniHelper::getStaticMethodInfo(minfo,
  6. "com/ai/ommr/OhMonsterMR4Android","testFunWithIntAndRtn","(I)I");
  7. jint_int;
  8. if(!isHave){
  9. CCLog("jni:此函数不存在");
  10. }else{
  11. CCLog("jni:此函数存在");
  12. //调用此函数
  13. _int=minfo.env->CallStaticIntMethod(minfo.classID,minfo.methodID,823);
  14. //尝试jint是否能正常接收返回的int值
  15. JniMethodInfominfo_ty;
  16. boolisHave=JniHelper::getStaticMethodInfo(minfo_ty,"com/ai/ommr/OhMonsterMR4Android","testFunWithInt","(I)V");
  17. if(isHave){
  18. minfo_ty.env->CallStaticVoidMethod(minfo_ty.classID,minfo_ty.methodID,_int);
  19. }
  20. }
  21. CCLog("jni-java函数执行完毕");
  22. #endif
Android(Java) 代码:

  1. //静态函数示例3.有参数,有返回值
  2. publicstaticinttestFunWithIntAndRtn(int_int){
  3. Log.e("Himi","静态函数示例1.有参数,有返回值;传入的参数int="+_int);
  4. return_int+1000;
  5. }

运行截图:

示例代码段4:

Xcode 代码:

  1. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)//判断当前是否为Android平台
  2. JniMethodInfominfo;//定义Jni函数信息结构体
  3. //getStaticMethodInfo次函数返回一个bool值表示是否找到此函数
  4. boolisHave=JniHelper::getStaticMethodInfo(minfo,"com/ai/ommr/OhMonsterMR4Android","testFunWithStringAndRtn","(I)Ljava/lang/String;");
  5. jobjectjobj;
  6. if(!isHave){
  7. CCLog("jni:此函数不存在");
  8. }else{
  9. CCLog("jni:此函数存在");
  10. //调用此函数
  11. jobj=minfo.env->CallStaticObjectMethod(minfo.classID,minfo.methodID,823);
  12. }
  13. CCLog("jni-java函数执行完毕");
  14. #endif
Android(Java) 代码:

  1. //静态函数示例4.有参数,有返回值(String类型)
  2. publicstaticStringtestFunWithStringAndRtn(int_int){
  3. Log.e("Himi","静态函数示例4.有参数,有返回值(String类型);int="+_int);
  4. return"yes,return'String'isOK--byHimi";
  5. }

运行截图:

示例代码段5:

Xcode 代码:

  1. #if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)//判断当前是否为Android平台
  2. JniMethodInfominfo;//定义Jni函数信息结构体
  3. //getStaticMethodInfo次函数返回一个bool值表示是否找到此函数
  4. boolisHave=JniHelper::getStaticMethodInfo(minfo,
  5. "com/ai/ommr/OhMonsterMR4Android",//类的路径
  6. "rtnActivity",//方法名
  7. "()Ljava/lang/Object;");//括号里的是参数,后面的是返回值。
  8. jobjectjobj;
  9. if(isHave){
  10. jobj=minfo.env->CallStaticObjectMethod(minfo.classID,minfo.methodID);
  11. }
  12. CCLog("正确获取到jobj");
  13. //
  14. isHave=JniHelper::getMethodInfo(minfo,
  15. "com/ai/ommr/OhMonsterMR4Android",//类的路径
  16. "nostaticFun",//方法名
  17. "()V");//括号里的是参数,后面的是返回值。
  18. if(isHave){
  19. minfo.env->CallVoidMethod(jobj,minfo.methodID);
  20. }
  21. CCLog("jni-java函数执行完毕");
  22. #endif
Java 代码:

  1. //----函数示例之非静态函数调用
  2. //(先获取个对象)
  3. publicstaticActivityactInstance;//定义单例
  4. publicstaticObjectrtnActivity(){
  5. returnactInstance;
  6. }
  7. //使用此对象进行调用非静态函数
  8. publicvoidnostaticFun(){
  9. Log.e("Himi","nostaticFunctionisOK-ByHimi");
  10. }

运行截图:

下面来介绍一些让人棘手的多参传递问题:

JNI编程:c++ 调用java 对象

用C++调用Java的java.lang.String类为例:

1. Object类出创建JVM。

使用Java类之前必须要创建JVM环境。JDK由java.exe来完成。本文有Object类的静态方法BeginJVM来创建,用EndJVM来关闭。

创建JVM之后会在创建2个变量,分别是JNIEnv* env和JavaVM* jvm,JNIEnv上文已经说明,JavaVM,顾名思义,代表Java虚拟机,用它来关闭JVM。

Object类的头文件

#include "jni.h"

class Object

{

public:

static bool BeginJVM();

static bool EndJVM();

Object();

virtual ~Object();

protected:

static JNIEnv* env;

static JavaVM* jvm;

};

object.cpp代码

#include "stdafx.h"

#include "JavaClasses.h"

#include "Object.h"

Object::Object()

{}

Object::~Object()

{}

JNIEnv* Object::env=NULL;

JavaVM* Object::jvm=NULL;

//创建JVM

bool Object::BeginJVM()

{

JavaVMOption options[3];

JavaVMInitArgs vm_args;

//各种参数

options[0].optionString="-Xmx128m";

options[1].optionString="-Verbose:gc";

options[2].optionString="-Djava.class.path=.";

vm_args.version=JNI_VERSION_1_2;

vm_args.options=options;

vm_args.nOptions=3;

//创建JVM,获得jvm和env

int res = JNI_CreateJavaVM(&jvm,(void **)&env, &vm_args);

return true;

}

bool Object::EndJVM()

{

//关闭JVM

jvm->DestroyJavaVM();

return true;

}

2. C++的String类调用java.lang.String类方法

编写C++版的String类,调用java String类方法。调用的方法如下:

String replaceAll(String regex, String replacement);

boolean endsWith(String str);

int indexOf(String str);

int compareTo(String anotherString);

char charAt(int i);

String的头文件:

class String :public Object

{

public:

//与要调用的Java方法名一致。

const char * replaceAll(char *regex,char *replacement);

bool endsWith(char * str);

int indexOf(char * str);

int compareTo(char *anotherString);

char charAt(int i);

String(char *str);

virtual ~String();

};

实现:

#include "stdafx.h"

#include "String.h"

#include "jni.h"

using namespace std;

jclass clazz; //全局变量,用来传递class

jobject object; //全局变量,用来传递object

String::String(char *str)

{

jstring jstr;

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

//获得java.lang.String类

clazz=Object::env->FindClass("java/lang/String");

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

//获得String(String str)构造体

jmethodID mid= Object::env->GetMethodID(clazz,"<init>", "(Ljava/lang/String;)V");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

//将字符串封装为jstring。

jstr = Object::env->NewStringUTF(str);

if (jstr == 0) {

cerr << "Out of memory" <<endl;

exit(-1);

}

cout << "invoking method" << endl;

//创建一个java.lang.String对象。

object=Object::env->NewObject(clazz,mid,jstr);

}

String::~String()

{}

char String::charAt(int i)

{

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

if (object ==0 ){

cout << "String object is not created" << endl;

exit(-1);

}

jmethodID mid;

//获得charAt方法,(I)C表示 参数为int型,返回char型。详细参见JNI规范

mid= Object::env->GetMethodID(clazz,"charAt", "(I)C");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

jint ji=i;

cout << "invoking method" << endl;

//调用charAt

jchar z=Object::env->CallCharMethod(object,mid,i);

//返回结果。

return z;

}

int String::compareTo(char *anotherString)

{

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

if (object ==0 ){

cout << "String object is not created" << endl;

exit(-1);

}

jmethodID mid;

//(Ljava/lang/String;)I表示参数为java.lang.String,返回int

mid= Object::env->GetMethodID(clazz,"compareTo", "(Ljava/lang/String;)I");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

jstring jstr = Object::env->NewStringUTF(anotherString);

cout << "invoking method" << endl;

//调用方法

jint z=Object::env->CallIntMethod(object,mid,jstr);

//返回结果

return z;

}

int String::indexOf(char *str)

{

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

if (object ==0 ){

cout << "String object is not created" << endl;

exit(-1);

}

jmethodID mid;

mid= Object::env->GetMethodID(clazz,"indexOf", "(Ljava/lang/String;)I");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

jstring jstr = Object::env->NewStringUTF(str);

cout << "invoking method" << endl;

jint z=Object::env->CallIntMethod(object,mid,jstr);

return z;

}

bool String::endsWith(char *str)

{

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

if (object ==0 ){

cout << "String object is not created" << endl;

exit(-1);

}

jmethodID mid;

mid= Object::env->GetMethodID(clazz,"endsWith", "(Ljava/lang/String;)Z");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

jstring jstr = Object::env->NewStringUTF(str);

cout << "invoking method" << endl;

bool z=Object::env->CallBooleanMethod(object,mid,jstr);

return z;

}

const char * String::replaceAll(char *regex, char *replacement)

{

if (Object::env ==NULL)

{

cout << "JVM is not created" << endl;

exit(-1);

}

if (clazz ==0 ){

cout << "Class is not found" << endl;

exit(-1);

}

if (object ==0 ){

cout << "String object is not created" << endl;

exit(-1);

}

jmethodID mid;

mid= Object::env->GetMethodID(clazz,"replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

if (mid==0){

cerr<< "GetMethodID Error for class" << endl;

exit(-1);

}

jvalue array[2];

jstring jreg = Object::env->NewStringUTF(regex);

jstring jstr = Object::env->NewStringUTF(replacement);

array[0].l=jreg;

array[1].l=jstr;

cout << "invoking method" << endl;

//传入参数,调用replaceAll方法

jobject z=Object::env->CallObjectMethodA(object,mid,array);

const char *result=Object::env->GetStringUTFChars((jstring)z, 0);

return (const char *)result;

}

3.测试

编写测试代码

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

int nRetCode = 0;

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))

{

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}

else

{

//创建JVM

Object::BeginJVM();

String test("hello");

//调用replaceAll

const char *result=test.replaceAll("l","z");

//返回结果

cout<< result <<endl;

//关闭JVM

Object::EndJVM();

}

return nRetCode;

}

4.运行

编译需要 jni.h和jvm.lib文件。

jni.h在[JAVA_HOME]\include

jvm.lib在[JAVA_HOME]\lib

运行需要jvm.dll

jvm.dll在[JAVA_HOME]\ jre\bin\client

运行结果如下:

invoking method

invoking method

hezzo

Press any key to continue



分享到:
评论

相关推荐

    ocos2d-x 通过JNI实现c/c++和Android的java层函数互调

    cocos2d-x 通过JNI实现c/c++和Android的java层函数互调, 本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。 (2)通过c++函数调用Android的java层函数,显示一...

    cocos2d-x 通过JNI实现c/c++和Android的java层函数互调-源码

    cocos2d-x 通过JNI实现c/c++和Android的java层函数互调-源码 详情请移步到:http://codingnow.cn/program/992.html

    JNI(c++与Java互调)cocos2d-x_3.x和android studio 3.0

    1.JNI(c++与Java互调)cocos2d-x_3.x和android studio 3.0 2.用的是cocos2d-x原始空项目做的。

    Cocos2d-x实战:JS卷——Cocos2d-JS开发

    资源名称:Cocos2d-x实战:JS卷——Cocos2d-JS开发内容简介:本书是介绍Cocos2d-x游戏编程和开发技术书籍,介绍了使用Cocos2d-JS中核心类、瓦片地图、物理引擎、音乐音效、数据持久化、网络通信、性能优化、多平台...

    Cocos2d-x游戏编程——C++篇 .iso

    Cocos2d-x游戏编程——C++篇(电子工业出版社,徐飞 著)书本配套的光盘代码,

    cocos2d-x-3.2旧版引擎下载

    cocos2d-x-3.2下载,不多说。或者可以下载另一个资源 cocos引擎老版本集合(cocos2d-x-2.2.1 - 3.5) http://download.csdn.net/download/crazymagicdc/9982656

    cocos2d-x事件类

    在使用cocos2d-x开发游戏的过程中,为了实现逻辑和显示相分离。 在下通宵了一个晚上,写出了该事件类。 谨记,该事件只能用于cocos2d-x中。 事件发送者需要继承EventDispatcher类 事件接收者需要继承EventHandle类...

    cocos2d-x-2.1.5

    cocos2d-x-2.1.5

    Cocos2d-x高级开发教程

    Cocos2d-x是移动跨平台开发最流行的游戏引擎,而本书是一本很全面的、比较‘接地气’的游戏开发教程。书中汇聚了热门手机游戏《捕鱼达人》开发的实战经验,作者从最基础的内容开始,逐步深入地介绍了Cocos2d-x的相关...

    大富翁手机游戏开发实战基于Cocos2d-x3.2引擎

    本书根据大富翁项目一一展开讲解游戏开发过程中涉及的各方面内容,读者可以通过这个游戏的开发,全面掌握Cocos2d-x游戏开发的方法和技巧。 本书理论和实践相结合, 资源太大,传百度网盘了,链接在附件中,有需要的...

    Cocos2D-X游戏开发技术精解

    资源名称:Cocos2D-X游戏开发技术精解内容简介:Cocos2D-X是一款支持多平台的 2D手机游戏引擎,支持iOS、Android、BlackBerry等众多平台。当前,很多移动平台流行的游戏,都是基于Cocos2D-X开发的。 《Cocos2D-X...

    cocos2d-x实战项目

    cocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML文件读取与骨骼动画.rarcocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML...

    Cocos2D-X游戏开发技术精解.pdf

    《Cocos2D-X游戏开发技术精解》详细介绍如何使用Cocos2D-X引擎开发自己的移动平台游戏。全书共15章,主要内容包括:Cocos2D-X引擎简介;如何建立跨平台的开发环境;引擎的核心模块——渲染框架;如何实现动态画面和...

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    精通COCOS2D-X游戏开发 基础卷_2016.4-P399-13961841.pdf

    精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发

    cocos2d-x-3.0 类图

    这是我重新弄的cocos2d-x-3.0的类图.之前别人兄台弄的,有些不全面,有些地方错误.我这个可以说是最新的了.每个类添加了中文的详细注解,同时也添加了中文的类名称翻译.这样对cocos2d-x-3.0的框架比较好上手. 有兴趣的...

    Cocos2d-x 3.x游戏开发实战pdf含目录

    Cocos2d-x 3.x游戏开发实战pdf含目录,内容详细,强烈推荐给大家。

    Cocos2d-x 2.0.1 版本用CCScrollView实现帮助页面

    Cocos2d-x 2.0.1 版本用CCScrollView实现帮助页面,请使用最新版的Cocos2d-x。 http://blog.csdn.net/toss156/article/details/7884207

    cocos2d-x实战 c++卷教程及完整源码

    cocos2d-x实战 c++卷教程及完整源码下载,使用最新cocos2d-x-3.14版本,在xcode7.3上已编译通过。 解决相关问题 1、解决源程序在高版本上无法编译问题 2、解决源程序中文注释部分,xcode上显示乱码问题 3、根据书籍...

    COCOS2D-X 捕鱼达人 (VS2010 C++)

    cocos2d-x2.25引擎建立的捕鱼达人,参照了《Cocos2d-x高级开发教程:制作自己的〈捕鱼达人〉》一书并做了改动。将代码导入cocos2d的projects文件夹内自创的工程文件夹里的proj.win32文件夹,resoutses则放在对应工程...

Global site tag (gtag.js) - Google Analytics