以下内容主要参考深入理解Android卷1.
JNI函数动态注册:
使用这个数据结构存储一个JNI函数的注册信息:
typedef struct {
//Java中native函数的名字,不用携带包的路径。例如“native_init“。
constchar* name;
//Java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合。
const char* signature;
void* fnPtr; //JNI层对应函数的函数指针,注意它是void*类型。
} JNINativeMethod;
从以上成员看出java中声明的native函数好像可以对应上该jni文件中的函数,但是实际上jni函数的在这个结构上是唯一的,但是java声明的不是,因为不带包路径,只是一个函数名,怎么知道这个函数是哪个类的呢,如果其他java文件也有这样一个同名的native声明呢?其实在注册时,会去获取对应的java类对象(Class类型的对象)。
为JNI动态库中的所有JNI函数建立一个JNINativeMethod数组,注册就用这个数组作为参数。示例:
static JNINativeMethod g_methods[] = {
{"nativeSetBlueLightFilterStrength", "(I)Z", (void*)nativeSetBlueLightFilterStrength},
{"nativeGetBlueLightFilterStrength", "()I", (void*)nativeGetBlueLightFilterStrength},
{"nativeEnableBlueLightFilter", "(Z)Z", (void*)nativeEnableBlueLightFilter},
{"nativeIsBlueLightFilterEnabled", "()Z", (void*)nativeIsBlueLightFilterEnabled},
{"nativeGetBlueLightFilterStrengthRange", "()I", (void*)nativeGetBlueLightFilterStrengthRange},
{"nativeBlueLightFilterInit", "()Z", (void*)nativeBlueLightFilterInit},
};
JNI函数签名:
JNI规范定义的函数签名信息格式:
(参数1类型标示参数2类型标示...参数n类型标示)返回值类型标示
比较繁琐,具体编码时,读者可以定义字符串宏
类型标示示意表
类型标示 |
Java类型 |
类型标示 |
Java类型 |
Z |
boolean |
F |
float |
B |
byte |
D |
double |
C |
char |
Ljava/lang/String; |
String |
S |
short |
[I |
int[] |
I |
int |
[Lava/lang/object; |
Object[] |
J |
long |
上面列出了一些常用的类型标示,如果Java类型是数组,则标示中会有一个“[”,另外,引用类型(除基本类型的数组外)的标示最后都有一个“;”,返回值签名时也是要加分号的
函数签名小例子
函数签名 |
Java函数 |
“()Ljava/lang/String;” |
String f() |
“(ILjava/lang/Class;)J” |
long f(int i, Class c) |
“([B)V” |
void f(byte[] bytes) |
当Java层通过System.loadLibrary加载完JNI动态库后,紧接着会查找该库中一个叫JNI_OnLoad的函数,如果有,就调用它,而动态注册的工作就是在这里完成的。
在JNI_OnLoad函数中注册会用到一下两行代码:
/*
env指向一个JNIEnv结构体,classname为对应的Java类名(全路径名,包名+类名),由于
JNINativeMethod中使用的函数名并非全路径名,所以要指明是哪个类。
*/
jclass clazz = (*env)->FindClass(env, className);
//调用JNIEnv的RegisterNatives函数,注册关联关系。
(*env)->RegisterNatives(env, clazz, gMethods,numMethods);
示例:
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className)