之前的文章 《简单的手电筒程序(基于系统驱动节点)》,我们讲了如何通过JNI的方法修改文件节点,当时用的是静态注册的方法,即JAVA层在load so的时候按照 Java_<包名>_<类名>_<方法名> 的命名规则在Native层寻找对应的处理函数,但是这个方法虽然简单,但是也存在一定的弊端: 1. 初次调用native函数时需要根据命名规则建立对应关系,影响效率; 2. native函数过长的命名会造成管理不方便。所以接下来我们会介绍动态注册的方法。
所谓动态注册,其实就是我们自己在代码中建立映射关系,然后在JVM中注册,这样,Jvm就可以直接通过我们建立的函数映射表来调用对应的函数,而不用系统通过命名规范去搜索建立。
我们会以 《简单的手电筒程序(基于系统驱动节点)》 为例,将其改造成通过动态注册的方法,改造后如下:
#include<jni.h>
#include<stdio.h>
#include <fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include"com_saberhao_bulbjni_BulbSwitch.h"
#include <android/log.h>
#include <unistd.h>
#include "JNIHelp.h"
#define LOG_TAG "BulbJNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define TRUNON "1"
#define TRUNOFF "0"
FILE *fp;
int fd;
int fd0;
void Native_TurnOn (JNIEnv *, jobject)
{
fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);
if(fd < 0)
{
LOGE("[turn on]open device error ");
}else{
LOGI("turn on the flash");
write(fd,TRUNON,sizeof(TRUNON));
}
close(fd);
if(fd0 < 0)
{
LOGE("[turn on]open test0 device error ");
}else{
//rewind(fp);
LOGI("turn on test0 the flash");
write(fd0,TRUNON,sizeof(TRUNON));
}
close(fd0);
}
void Native_TurnOff(JNIEnv *, jobject)
{
fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);
if(fd < 0)
{
LOGE("[turn off]open device error ");
}else{
LOGI("turn off the flash");
write(fd,TRUNOFF,sizeof(TRUNOFF));
}
close(fd);
}
/**
* 函数映射表
*/
static JNINativeMethod gMethods[] = {
{
"TurnOn", //Java 层函数名
"()V", //(参数类型) 返回值
(void*)Native_TurnOn //Native 层函数类型
},
{
"TurnOff", //Java 层函数名
"()V", //(参数类型) 返回值
(void*)Native_TurnOff //Native 层函数类型
},
};
int register_BulbJni(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/saberhao/bulbjni/BulbSwitch ", gMethods, NELEM(gMethods));
}
/*
* System.loadLibrary("lib")时调用
* 如果成功返回JNI版本, 失败返回-1
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
//JNI_OnLoad 中进行动态注册
if (!register_BulbJni(env)) {
return -1;
}
//成功
result = JNI_VERSION_1_4;
return result;
}
有两个地方是要注意的:
1. jniRegisterNativeMethods和NELEM都是在头文件JNIHelp.h定义的, 需要添加 头文件
#include "JNIHelp.h"
2.再Android.mk文件加上
LOCAL_SHARED_LIBRARIES +=libnativehelper
重点难点也是两个
1. JNINativeMethod 这个结构体,Java与JNI就是通过它来建立联系,它在jni.h中被定义,其结构内容如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数
参考文章:
http://blog.csdn.net/flydream0/article/details/7371692
http://blog.csdn.net/chenfeng0104/article/details/7088600