JNI基础
JNI 全称 Java Native Interface, 是java代码与native代码(一般是把c,c++这些直接编译成目标机器执行的代码加本地代码)实现互操作的接口, 是Java与c,c++的粘合剂
Java是运行在JVM上的语言, JVM运行的是Java的字节码,即中间码, 因此Java与调用本地代码,只能通过JNI
JNI程序编译运行流程
声明Java的native 方法
C++实现native方法的JNI函数
将所有JNI函数编译成动态链接库(linux为 .so, windows为 .dll, MacOS为 .dylib)
调用Java native方法前先加载库文件
static{ System.load(".so文件路径") // or System.loadLibrary("去掉lib的so文件名") }
调用native 方法
Java与c++ 的绑定的几种方法
1.用 javah 命令,生成对应的C语言头文件
javah -classpath D:\我的文档\workspace\PrepareForExam\bin -jni
# -classpath <路径> 用于装入类的路径
# -jni 生成 JNI样式的头文件(默认)
2. 手写C++接口函数
extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_stepTest(JNIEnv *env,jobject me,jint i);
注意
extern "C"
必须要有,否则会导致编译出来的函数找不到函数命名规则为: Java_{包路径+类名+方法名}, 方法名中每出现一个下划线, 要在下划线后面加数字1,如:
extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_step_1Test(JNIEnv *env,jobject me,jint i);
对应Java的
com.imi.sdk.jintest.CameraPreviewFragment.step_Test()
每个JNI函数的第一个参数都位
JNIEnv *env
, 第二个参数位jobject me
(对象方法) 或者jclass cls
(静态方法)JNI函数被调用时不会检测参数类型, 因此你写错参数位置的结果只会是莫名其妙的崩
3. 使用第三方工具生成
swig 是个很好的将c++的代码生成JNI接口的软件,你可以不用写一行JNI代码就能实现Java调用c++功能
4. 在JNI_OnLoad()
中或者运行时动态注册JNI接口
static const JNINativeMethod gMethods[] = {
{"getUrl", "()Ljava/lang/String;", (jstring*)getUrl},
{"setData","([BI)V",(void*)setData}
};
//
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL; //注册时在JNIEnv中实现的,所以必须首先获取它
jint result = -1;
if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本
return -1;
myClass = env)->FindClass(kClassName);
if(myClass == NULL)
{
printf("cannot get class:%s\n", kClassName);
return -1;
}
if(env->RegisterNatives(myClass,gMethods,sizeof(gMethods)/sizeof(gMethods[0]))<0)
{
printf("register native method failed!\n");
return -1;
}
printf("--------JNI_OnLoad-----");
return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}