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

cocos2d-x 通过JNI实现cc++和Android的java层函数互调,第1张

概述文章摘要: 本文主要实现两个功能: (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,必须得… @H_301_9@ 本文主要实现两个功能:
(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 */ typedef uint8_t jboolean; /* unsigned 8 bits */ int8_t jbyte; /* signed 8 bits */ uint16_t jchar; /* unsigned 16 bits */ int16_t Jshort; /* signed 16 bits */ int32_t jint; /* signed 32 bits */ int64_t jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ double jdouble; /* 64-bit IEEE 754 */ #else unsigned char jboolean; /* unsigned 8 bits */ signed char jbyte; /* signed 8 bits */ short jchar; /* unsigned 16 bits */ Jshort; /* signed 16 bits */ int jint; /* signed 32 bits */ long long jlong; /* signed 64 bits */ /* 32-bit IEEE 754 */ /* 64-bit IEEE 754 */ #endif /* "cardinal indices and sizes" */ jint Jsize; #ifdef __cplusplus /* * Reference types,in C++ */ class _jobject {}; _jclass : public _jobject {}; _Jstring : _jobject {}; _jarray : _jobject {}; _jobjectArray : _jarray {}; _jbooleanArray : _jarray {}; _jbyteArray : _jarray {}; _jchararray : _jarray {}; _JshortArray : _jarray {}; @H_334_403@ _jintArray : _jarray {}; _jlongArray : _jarray {}; _jfloatArray : _jarray {}; _jdoubleArray : _jarray {}; _jthrowable : _jobject {}; _jobject* jobject; _jclass* jclass; _Jstring* Jstring; _jarray* jarray; _jobjectArray* jobjectArray; _jbooleanArray* jbooleanArray; _jbyteArray* jbyteArray; _jchararray* jchararray; _JshortArray* JshortArray; _jintArray* jintArray; _jlongArray* jlongArray; _jfloatArray* jfloatArray; _jdoubleArray* jdoubleArray; _jthrowable* jthrowable; _jobject* jweak; #else /* not __cplusplus */ /* */ typedef voID * jobject; jobject jclass; jobject Jstring; jobject jarray; jarray jobjectArray; jarray jbooleanArray; jarray jbyteArray; jarray jchararray; jarray JshortArray; jarray jintArray; jarray jlongArray; jarray jfloatArray; jarray jdoubleArray; jobject jthrowable; jobject jweak; #endif /* not __cplusplus */
@H_301_9@ 我们经常用到的是jnienv*,它是一个c结构体,封装了许多常用的函数,如:

18
struct _jnienv { /* do not rename this; it does not seem to be entirely opaque */ const JNINativeInterface* functions; #if defined(__cplusplus) jint GetVersion() { return functions->GetVersion( this ); } jclass defineClass( const *name,jobject loader, const jbyte* buf, Jsize bufLen) functions->defineClass( ,name,loader,buf,bufLen); } jclass FindClass( * name) functions->FindClass( // 这里省略其他函数... }
@H_301_9@ cocos2d-x引擎对jni的 *** 作进行了封装,提供了一个非常好用的类:JniHelper,定义了一些常用的接口,该文件位于cocos2dx/platform/androID/jni目录下。下面看看JniHelper.h源码:

23
JniMethodInfo_ { jnienv * env; jclass classID; jmethodID methodID; } JniMethodInfo; CC_DLL JniHelper { : static JavaVM* getJavaVM(); static setJavaVM(JavaVM *javaVM); * getExternalAssetPath(); setExternalAssetPath( * externalAssetPath); jclass getClassID( *classname,jnienv *env=0); static bool getStaticmethodInfo(JniMethodInfo &methodinfo,monospace!important; Font-size:1em!important; min-height:auto!important"> *methodname,monospace!important; Font-size:1em!important; min-height:auto!important"> *paramCode); getmethodInfo(JniMethodInfo &methodinfo,monospace!important; Font-size:1em!important; min-height:auto!important"> *paramCode); std::string Jstring2string(Jstring str); private : JavaVM *m_psJavaVM; std::string m_externalAssetPath; };
@H_301_9@ 下面来解释JniHelper的两个常用函数:
(1)getStaticmethodInfo
用来判断Java的类静态函数是否存在,并初始化结构体JniMethodInfo,该结构体封装了jnienv*和java.lang.class对象、函数ID。这样就可以使用jnienv*调用 CallStaticXXXMethod(jclass clazz,jmethodID methodID,…)和 CallXXXMethod(jobject obj,…)等常用函数(XXX替换为函数返回值类型,如:VoID,Int等)。
第一个参数为JniMethodInfo,第二个参数是类的绝对路径,第三个参数是函数名,第四个参数是函数签名(参数和返回类型),示例代码如下:

4
if (JniHelper::getStaticmethodInfo(t,CLASS_name, "showTipDialog" "(Ljava/lang/String;Ljava/lang/String;)V" )) { //... }
@H_301_9@ 关于类型签名,请对照下图:

@H_301_9@ (2)getmethodInfo
该函数与getStaticmethodInfo类似,用于java类的非静态函数。

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

8
private static Handler mHandler; public static voID init(Handler handler) { @H_419_903@ JniTestHelper.mHandler = handler; } native setPackagename(String packagename);
@H_301_9@ (3)打开JniTest.java,在onCreate函数中添加下面的代码:

5
protected voID onCreate(Bundle savedInstanceState){ @H_419_903@ super .onCreate(savedInstanceState); @H_419_903@JniTestHelper.init(mHandler); @H_419_903@JniTestHelper.setPackagename( this .getPackagename()); @H_419_903@}
@H_301_9@ (4)java层的代码已经完成了,下面来编写jni层代码,在/jni/hellocpp/下创建test.h和test.cpp文件,test.h文件暂时不添加任何函数,代码如下:
test.h

4
#ifndef TEST_H #define TEST_H #endif
@H_301_9@ test.cpp

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" using namespace cocos2d; extern "C" { Java_com_alexzhou_jni_JniTestHelper_setPackagename(jnienv *env,jobject thiz,Jstring packagename) { *pkgname = env->GetStringUTFChars(packagename,NulL); setPackagename(pkgname); env->ReleaseStringUTFChars(packagename,pkgname); } }
@H_301_9@ 必须加上extern “C”,声明以c语言的方式进行编译,因为c++和c在编译时生成的函数签名不一样,可以在网上查找相关资料,不然运行的时候会出现链接错误。
(5)现在编写c++函数,在Classes目录下创建JniTest.h,代码如下:

13
#ifndef JNI_TEST_H #define JNI_TEST_H #include "cocos2d.h" cocos2d; setPackagename( *packagename) { cclog( "packagename: %s" } #endif
@H_301_9@ (6)修改jni/AndroID.mk文件的LOCAL_SRC_fileS值 ,内容如下:

2
LOCAL_SRC_fileS := hellocpp /main .cpp \ hellocpp /test .cpp
@H_301_9@ (7)编译运行,因为我是使用cygwin编译的,而且AndroID项目不在cocos2d-x的根目录下,所以需要修改build_native.sh,修改COCOS2DX_ROOT和NDK_MODulE_PATH的值,把当前cocos2d-x项目的路径添加到NDK_MODulE_PATH,修改后的值:

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}"
@H_301_9@ 运行结果:

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

12
exitApp(); showTipDialog( final String Title, String text) Message msg = mHandler.obtainMessage(); @H_419_903@msg.what = JniTest.SHOW_DIALOG; @H_419_903@DialogMessage dm = new DialogMessage(); @H_419_903@dm.Title = Title; @H_419_903@dm.msg = text; @H_419_903@msg.obj = dm; @H_419_903@msg.sendToTarget(); }
@H_301_9@ (9)创建一个DialogMessage.java,封装dialog要显示的数据。

11
/** author:alexzhou email :zhoujiangbohai@163.com date :2012-12-14 @H_419_903@ **/ class DialogMessage { public String Title; @H_419_903@String msg; }
@H_301_9@ (10) 修改JniTest.java,添加显示对话框的函数:

33
final int SHOW_DIALOG = 0x0001 ; private Handler mHandler = Handler() @H_419_903@ @OverrIDe @H_419_903@ handleMessage(Message msg) { switch (msg.what) @H_419_903@{ case SHOW_DIALOG: @H_419_903@DialogMessage dm = (DialogMessage)msg.obj; @H_419_903@AlertDialog.Builder(JniTest. ) @H_419_903@.setTitle(dm.Title) @H_419_903@.setMessage(dm.msg).setNegativebutton( "cancle" DialogInterface.OnClickListener() { @OverrIDe @H_419_903@ onClick(DialogInterface dialog,153)!important">int which) { @H_419_903@dialog.dismiss(); @H_419_903@} @H_419_903@}) @H_419_903@.setPositivebutton( "Ok" @OverrIDe @H_419_903@which) { @H_419_903@dialog.dismiss(); @H_419_903@JniTestHelper.exitApp(); @H_419_903@} @H_419_903@}) @H_419_903@.create().show(); break ; @H_419_903@} @H_419_903@} @H_419_903@};
@H_301_9@ (11)在test.h和test.cpp中添加显示对话框的接口:
test.h

"C"{showTipDialog( *Title,monospace!important; Font-size:1em!important; min-height:auto!important"> *msg);}
@H_301_9@ test.cpp

28
*msg) { JniMethodInfo t; )) { 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); } } { setPackagename(pkgname); } Java_com_alexzhou_jni_JniTestHelper_exitApp(jnienv *env,jobject thiz) { exitApp(); } }
@H_301_9@ (12) 修改Classes目录下的JniTest.h,添加代码:

exitApp()CCDirector::sharedDirector()->end();}
@H_301_9@ (13)到此为止,所有代码都已经完成了,代码比较简单就不详细解释了,现在编译运行,效果如下:

@H_301_9@ 源码下载地址:http://download.csdn.net/detail/zhoujianghai/4890792

@H_301_9@

@H_301_9@ from:http://codingnow.cn/cocos2d-x/992.html

总结

以上是内存溢出为你收集整理的cocos2d-x 通过JNI实现c/c++和Android的java层函数互调全部内容,希望文章能够帮你解决cocos2d-x 通过JNI实现c/c++和Android的java层函数互调所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1069107.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存