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源码地址