JNI笔记

99 阅读2分钟

jni函数组成释义:

extern "C"
//申明为c 语言,jni是用c实现的,
// 不申明的话会用c++函数,而c++会将参数的类型编译进来生成函数名,java调用方法名找不到
//导入c文件的话需要加上 extern "C"{ include<c文件名>}
JNIEXPORT jint JNICALL
//这个是静态注册
extern "C"
//JNIEXPORT:表示宏,值为__attribute__ ((visibility ("default"))),有两个值,还有一个是hidden,意为函数不可见
//jint:返回值
//JNICALL:表示是jni函数,无实际意义
JNIEXPORT void JNICALL
//jni函数名组成:Java_包名_类名_函数名
//Java + cpm.example.anative + /jni/JniActivity + fun
Java_com_example_anative_jni_JniActivity_fun(JNIEnv *env, jobject thiz) {
    //env:相当于一个工具类
    //thiz:引用jni的类地址。static 参数为jclass ,非静态是jobject
}

jni函数的使用:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_anative_jni_JniActivity_fun3(JNIEnv *env, jobject thiz, jstring str) {
    //str:java参数的引用地址
    //isCopy:是否需要拷贝,如果拷贝会生成一个字符串
    const char *str1 = env->GetStringUTFChars(str, 0);//将java中的string转化为c的char
    env->ReleaseStringChars(str, reinterpret_cast<const jchar *>(str1));//释放内存,c里面malloc的内存需要释放

    //c的字符串转java
    std::string str2 = "str2";
    jstring  str3 = env->NewStringUTF(str2.c_str());

    //c访问java变量,通过反射访问
    jclass class_variable = env->GetObjectClass(thiz);//拿到类地址
    jfieldID class_str_c_java_id = env->GetFieldID(class_variable, "str_c_java", "Ljava/lang/String;");//拿到变量地址
    env->SetObjectField(thiz, class_str_c_java_id, env->NewStringUTF("success"));//改变值,放入java的内存结构
//    NewStringUTF不需要释放,gcc会处理的,因为放在java的方法区的常量区。
//     只是JVM上的malloc内存,JVM将负责内存
//     疑问:jni里哪些是jvm创建的内存,哪些不是
    //c访问java函数,通过反射访问
    jclass class_function = env->GetObjectClass(thiz);
    jmethodID class_function_id = env->GetMethodID(class_function, "fun5", "(IB)Z");//拿到java方法的id
    env->CallBooleanMethod(thiz, class_function_id,2,0x1);//根据返回值确定调用的call函数,在里面输入java函数需要的值
}

jni和java以及c/c++的类型对比: image.png

jni中的方法签名: image.png

/**
 * jni静态注册是拼接方法名去so库遍历查找方法
 * jni动态注册是生成注册方法表,再拿着方法名直接去库里找.反编译的难度大。
 */