C/C++和Java的交互详解
安卓中支持c++(NDK)和java(SDK)语言,当使用到c++语言时,c++代码和java如何交互就尤为重要。在下载的NDK包中samples/hello-jni有一个简单的实例可以参考。
java调用C++
新建Android项目,创建如下类:
packagecom.example.testjni; publicclassTextJni{ //supporttoc static{ System.loadLibrary("jniinterface"); } publicstaticnativeintgetInt(); publicstaticnativeStringgetString(); }
上面声明了两个native方法,表示getInt和getString的方法实现将在c++(libjniinterface.so)中给出。
在classes目录下运行如下命令,以生成native对应的实现文件。
javahcom.example.testjni.TextJni #注意如果要有AndroidSDK的类需要指定classpath,如 javah-classpath/Users/Richard/dev/android/sdk/platforms/android-19/android.jar:./bin/classescom.togic.gameengine.GFRenderer
生成头文件拷贝出来,创建jni文件夹,并创建出cpp实现文件
com_example_testjni_TextJni.cpp: #include<stdio.h> #include<stdlib.h> #include"com_example_testjni_TextJni.h" intsum() { intx,y; x=100; y=1000; x+=y; returnx; } //实现com_example_textjni_textJNI.h的方法 JNIEXPORTjintJNICALLJava_com_example_testjni_TextJni_getInt(JNIEnv*env,jclasscls) { returnsum(); } JNIEXPORTjstringJNICALLJava_com_example_testjni_TextJni_getString(JNIEnv*env,jclasscls) { returnenv->NewStringUTF("HelloNDK!"); }
这里要用到交叉编译,组织c++代码需要用Android.mk。
新建一个Android.mk文件在jni/下
Android.mk: LOCAL_PATH:=$(callmy-dir) include$(CLEAR_VARS) LOCAL_MODULE:=jniinterface LOCAL_SRC_FILES:=com_example_testjni_TextJni.cpp #LOCAL_C_INCLUDES:=$(LOCAL_PATH) include$(BUILD_SHARED_LIBRARY)
然后就可以用NDK里的工具:ndk-build来生成动态链接库:libjniinterface.so
生成的库文件就可以被之前的Java文件调用了。
c++调用java
可以在上例中getString方法里利用JNI调用java:
JNIEXPORTjstringJNICALLJava_com_togic_testjni2_TextJni_getString(JNIEnv*env,jclasscls) { jclassTextJni; jobjectinstTextJni; jmethodIDgetCurrInt; JNIEnv*jniEnv=env; TextJni=jniEnv->FindClass("com/togic/testjni2/TextJni"); jmethodIDconstruction_id=jniEnv->GetMethodID(TextJni,"init","()V"); instTextJni=jniEnv->NewObject(TextJni,construction_id); getCurrInt=jniEnv->GetStaticMethodID(TextJni,"getCurrInt","()I"); //calljavastaticmethod jintjiref=jniEnv->CallStaticIntMethod(TextJni,getCurrInt); //clean jniEnv->DeleteLocalRef(TextJni); jniEnv->DeleteLocalRef(instTextJni); std::stringstrRef="HelloNDK!"+view->getStaticString(); returnenv->NewStringUTF(strRef.c_str()); }
首先值得注意的是jni.h里的函数区分c和c++语言两种接口,对于c++一般如下:
jclassclazz=env->FindClass(classname);
而对于c而言:
jclassclazz=(*env)->FindClass(env,classname);
GetMethodID中第三个参数表示方法签名,可以按如下方法获得:
javap-s包名.类名 得到方法的签名
附JNI数据类型转化
jstring转char*
constcharnativeString=(env)->GetStringUTFChars(env,javaString,0);
返回指向字符串的UTF-8字符数组的指针,该数组在被ReleaseStringUTFChars()释放前将一直有效。
(*env)->ReleaseStringUTFChars(env,javaString,nativeString);
char*转jstring
jstringjstr=(env)->NewStringUTF(env,charutf)
利用UTF-8字符数组构造新java.lang.String对象。
其他类型
全选复制放进笔记Java类型本地c类型说明
booleanjboolean无符号,8位
bytejbyte无符号,8位
charjchar无符号,16位
shortjshort有符号,16位
intjint有符号,32位
longjlong有符号,64位
floatjfloat32位
doublejdouble64位
voidvoidN/A