c/c++和java交互,需要找到雙方各自對應的函數或方法來調用。這種產生聯繫的方式有兩種方式,一個是靜態註冊,另一種事動態註冊。動態註冊是比靜態註冊的好處是不需要JNI那一套很長的命名。
其他的規則和靜態註冊無異,只是註冊的地方不同而已。
下面是動態註冊的方式。
/**
* 動態註冊
*/
extern "C" {
jstring stringFromJNI2(JNIEnv *env, jobject instance) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
jint add(JNIEnv *env, jclass clazz, jint a, jint b) {
LOGE("ADD!!");
return a + b;
}
#define JNIREG_CLASS "com/slzr/ndk/NDKManager"//指定要註冊的類
/**
* 方法對應表
*/
static JNINativeMethod gMethods[] = {
// {"stringFromJNI2", "()Ljava/lang/String;", (void *) stringFromJNI2},
{"add", "(II)I", (void *) add}
};
/*
* 爲某一個類註冊本地方法
*/
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods,
int numMethods) {
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* 爲所有類註冊本地方法
*/
static int registerNatives(JNIEnv *env) {
return registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0]));
}
/*
* System.loadLibrary("lib")時調用
* 如果成功返回JNI版本, 失敗返回-1
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
jint result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
assert(env != NULL);
if (!registerNatives(env)) {//註冊
return -1;
}
//成功
result = JNI_VERSION_1_6;
return result;
}
}
這裏說明一下,JNI_OnLoad
是System.loadLibrary
加載完動態庫執行的函數,寫在jni.h裏面。
registerNatives
寫本地的方法。gMethods
寫方法列表,第一參數是java裏面的方法名稱,第二參數是方法輸入參數,第三個參數是c/c++裏面對應的函數。它的結構類型如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
第二個參數可以參照java的反射。
字符 Java類型 C類型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
數組則以"["開始,用兩個字符表示。
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
gMethods裏面的第二參數()
表示輸入參數,有多少就寫多少進去。比如說兩個int參數,就寫(II)
。括號後面跟着的是返回值V
表示沒有返回值void。Ljava/lang/String;
對應是String類型。Ljava/lang/Object;
對應是Object類型。
在java層面仍然需要native 編寫。
public native int add(int a, int b);
附件:
demo源碼地址