转载请注明来自:Alex Zhou的程序世界,本文链接:http://codingnow.cn/cocos2d-x/992.html
本文主要实现两个功能:
(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相关的数据类型和接口。下面是相关代码片段:
# include <inttypes.h> /* C99 */ typedef uint8_t jboolean; /* unsigned 8 bits */ typedef int8_t jbyte; /* signed 8 bits */ typedef uint16_t jchar; /* unsigned 16 bits */ typedef int16_t jshort; /* signed 16 bits */ typedef int32_t jint; /* signed 32 bits */ typedef int64_t jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #else typedef unsigned char jboolean; /* unsigned 8 bits */ typedef signed char jbyte; /* signed 8 bits */ typedef unsigned short jchar; /* unsigned 16 bits */ typedef short jshort; /* signed 16 bits */ typedef int jint; /* signed 32 bits */ typedef long long jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #endif /* "cardinal indices and sizes" */ typedef jint 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. */ typedef void* jobject; typedef jobject jclass; typedef jobject jstring; typedef jobject jarray; typedef jarray jobjectArray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jobject jthrowable; typedef jobject jweak; #endif /* not __cplusplus */我们经常用到的是JNIEnv*,它是一个c结构体,封装了许多常用的函数,如:
struct _JNIEnv { /* do not rename this; it does not seem to be entirely opaque */ const struct JNINativeInterface* functions; #if defined(__cplusplus) jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte* buf, jsize bufLen) { return functions->DefineClass(this, name, loader, buf, bufLen); } jclass FindClass(const char* name) { return functions->FindClass(this, name); } // 这里省略其他函数... }
typedef struct JniMethodInfo_ { JNIEnv * env; jclass classID; jmethodID methodID; } JniMethodInfo; class CC_DLL JniHelper { public: static JavaVM* getJavaVM(); static void setJavaVM(JavaVM *javaVM); static const char* getExternalAssetPath(); static void setExternalAssetPath(const char* externalAssetPath); static jclass getClassID(const char *className, JNIEnv *env=0); 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); static std::string jstring2string(jstring str); private: static JavaVM *m_psJavaVM; static std::string m_externalAssetPath; };
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++调用的函数,添加如下代码:
private static Handler mHandler; public static void init(Handler handler) { JniTestHelper.mHandler = handler; } public static native void setPackageName(String packageName);
protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); JniTestHelper.init(mHandler); JniTestHelper.setPackageName(this.getPackageName()); }
test.h
#ifndef TEST_H #define TEST_H #endif
#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" { void Java_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName) { const char *pkgName = env->GetStringUTFChars(packageName, NULL); setPackageName(pkgName); env->ReleaseStringUTFChars(packageName, pkgName); } }
#ifndef JNI_TEST_H #define JNI_TEST_H #include "cocos2d.h" using namespace cocos2d; void setPackageName(const char *packageName) { CCLog("packageName: %s", packageName); } #endif
LOCAL_SRC_FILES := hellocpp/main.cpp \ hellocpp/test.cpp
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添加如下代码:
public static native void exitApp(); private static void showTipDialog(final String title, final String text) { Message msg = mHandler.obtainMessage(); msg.what = JniTest.SHOW_DIALOG; DialogMessage dm = new DialogMessage(); dm.title = title; dm.msg = text; msg.obj = dm; msg.sendToTarget(); }
/** author:alexzhou email :[email protected] date :2012-12-14 **/ public class DialogMessage { public String title; public String msg; }
public static final int SHOW_DIALOG = 0x0001; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch(msg.what) { case SHOW_DIALOG: DialogMessage dm = (DialogMessage)msg.obj; new AlertDialog.Builder(JniTest.this) .setTitle(dm.title) .setMessage(dm.msg).setNegativeButton("cancle", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .setPositiveButton("Ok", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); JniTestHelper.exitApp(); } }) .create().show(); break; } } };
extern "C" { void showTipDialog(const char *title, const char *msg); }
extern "C" { void showTipDialog(const char *title, const char *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); } } void Java_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName) { const char *pkgName = env->GetStringUTFChars(packageName, NULL); setPackageName(pkgName); env->ReleaseStringUTFChars(packageName, pkgName); } void Java_com_alexzhou_jni_JniTestHelper_exitApp(JNIEnv *env, jobject thiz) { exitApp(); } }
void exitApp() { CCDirector::sharedDirector()->end(); }
源码下载地址:http://download.csdn.net/detail/zhoujianghai/4890792