Java调用Native方法前,需要注册,将指定的Native方法与so中对应的方法绑定起来。
注册分为静态注册
和动态注册
一、静态注册
通过JNIEXPORT和JNICALL两个宏定义声明,在虚拟机加载so时发现上面两个宏定义的函数时就会链接到对应的Native方法。
规则为Java + 包名 + 类名 + 方法名
例如包名为com.leo.project,类名为RoomActivity
// Java native method
public native String showStringJNI();
// JNI method
JNIEXPORT jstring JNICALL
Java_com_leo_project_RoomActivity_showStringJNI(JNIEnv *env,jobject instance)
// Java native method
public native String showString_JNI();
// JNI method
JNIEXPORT jstring JNICALL
Java_com_leo_project_RoomActivity_showString_1JNI(JNIEnv *env,jobject instance)
二、动态注册
1. java中定义方法
public native void startServer(String ip, int port)
2.JNI声明
#include <jni.h>
extern "C" {
void native_startServer(JNIEnv *env,jobject obj,
jstring ip,jint port)
}
tips: extern "C"的作用是让C++编译器将extern "C"声明的代码当做C语言代码处理,可以避免C++因符号修饰导致代码不能和C语言库中的符号进行链接的问题
3.JNI注册
a.GetEnv(void** env,jint version)
参数<env>:env指针对象,通过该方法给env赋值
参数<version>:JNI版本
b.FindClass(const char* name)
参数<name>:为Java定义方法类的路径,例如:com/leo/project/jni/SocketJni
jclass jc = env->FindClass("com/leo/project/jni/SocketJni")
c.RegisterNatives(jclass clazz,const JNINativeMethod* methods,jint nMethods)
参数<clazz>:根据Java定义方法类的路径获得的对应jclass类
参数<methods>:根据方法名、参数、返回值定义的方法集合
参数<nMethods>:定义的方法数
d.JNINativeMethod
结构体
typedef struce {
const char* name; // 方法名
const char* signature; // 参数与返回值表示
void* fnPtr; // 步骤2声明的名字
} JNINativeMethod;
// 定义需注册的方法集合
static JNINativeMethod gMethods[] = {
{"startServer", "(Ljava/lang/String;I)V",(void *) native_startServer}
}
// 1. JNI_OnLoad方法中根据JavaVM获得JNIEnv
JNIEnv *env = NULL;
vm->GetEnv((void **) &env,JNI_VERSION_1_4)
// 2. 根据Java类路径获取jclass
jclass jc = env->FindClass("com/leo/project/jni/SocketJni")
// 3. 声明方法集合
static JNINativeMethod gMethods[] = {
{"startServer","(Ljava/lang/String;I)V",(void *) native_startServer}
}
// 4. 注册
env->RegisterNatives(jc,gMethods,NELEM(gMethods))