> 文章列表 > JNI使用总结

JNI使用总结

JNI使用总结

目录

  • 1. 静态
    • 1.1 访问Java类public成员变量
    • 1.2 访问Java类static成员变量
    • 1.3 访问Java类private成员变量
    • 1.4 访问Java类public方法
    • 1.5 访问Java类父类方法
    • 1.6 访问Java的int array
    • 1.7 访问Java传入对象的方法
    • 1.7 访问Java传入的类的ArrayList
  • 2. 动态注册
    • 2.1 步骤
    • 2.2 实现代码:

1. 静态

1.1 访问Java类public成员变量

JNIEXPORT jint JNICALL
Java_com_my_1test_jnidemo_MainActivity_addNum(JNIEnv *env,jobject jobj) {jclass jclazz = env->GetObjectClass(jobj);jfieldID fid = env->GetFieldID(jclazz, "num", "I");jint num = env->GetIntField(jobj, fid);num++;return num;
}

1.2 访问Java类static成员变量

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessStaticField(JNIEnv *env,jobject jobj)
{jclass jclazz = env->GetObjectClass(jobj);jfieldID fid  = env->GetStaticFieldID(jclazz, "name", "Ljava/lang/String;");jstring  name = (jstring)env->GetStaticObjectField(jclazz, fid);const char* str = env->GetStringUTFChars(name, JNI_FALSE);std::string ret = "hello ";ret.append(str);jstring new_ret = env->NewStringUTF(ret.c_str());env->SetStaticObjectField(jclazz, fid, new_ret);
}

1.3 访问Java类private成员变量

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessPrivateField(JNIEnv *env,jobject jobj)
{jclass jclazz = env->GetObjectClass(jobj);jfieldID fid  = env->GetFieldID(jclazz, "age", "I");jint     age  = env->GetIntField(jobj, fid);if (age > 18){age = 18;} else{age--;}env->SetIntField(jobj, fid, age);
}

1.4 访问Java类public方法

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessPublicMethod(JNIEnv *env,jobject jobj)
{jclass jclazz = env->GetObjectClass(jobj);jmethodID mid = env->GetMethodID(jclazz, "setSex", "(Ljava/lang/String;)V");char c[10] = "male";jstring jsex = env->NewStringUTF(c);env->CallVoidMethod(jobj, mid, jsex);
}

1.5 访问Java类父类方法

JNIEXPORT jstring JNICALL
Java_com_my_1test_jnidemo_MethodJni_accessSuperMethod(JNIEnv *env,jobject jobj)
{jclass jclazz = env->FindClass("com/my_test/jnidemo/SuperJni");if (jclazz == NULL){char c[] = "error";return env->NewStringUTF(c);}jmethodID mid = env->GetMethodID(jclazz, "hello", "(Ljava/lang/String;)Ljava/lang/String;");char c[10] = "male11";jstring jname = env->NewStringUTF(c);return (jstring)env->CallNonvirtualObjectMethod(jobj, jclazz, mid, jname);
}

1.6 访问Java的int array

JNIEXPORT jint JNICALL
Java_com_my_1test_jnidemo_MainActivity_intArrayMethod(JNIEnv *env,jobject jobj, jintArray arr_)
{jint len = 0, sum = 0;jint *arr = env->GetIntArrayElements(arr_, 0);len = env->GetArrayLength(arr_);jint i = 0;for (; i<len;i++){sum += arr[i];}env->ReleaseIntArrayElements(arr_, arr, 0);return sum;
}

1.7 访问Java传入对象的方法

JNIEXPORT jobject JNICALL
Java_com_my_1test_jnidemo_MainActivity_objectMethod(JNIEnv *env,jobject jobj, jobject person)
{jclass clazz = env->GetObjectClass(person);if (clazz == NULL){return env->NewStringUTF("cannot find class");}jmethodID mid = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");if (mid == NULL){return env->NewStringUTF("not find constructor method");}jstring name = env->NewStringUTF("cfanr");return env->NewObject(clazz, mid, 21, name);
}

1.7 访问Java传入的类的ArrayList

JNIEXPORT jobject JNICALL
Java_com_my_1test_jnidemo_MainActivity_personArrayListMethod(JNIEnv *env,jobject jobj, jobject persons)
{jclass clazz = env->GetObjectClass(persons);if (clazz == NULL){return env->NewStringUTF("not find class");}jmethodID constructMid = env->GetMethodID(clazz, "<init>", "()V");if (constructMid == NULL){return env->NewStringUTF("not find constructormethod");}jmethodID addMid = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");jclass personCls = env->FindClass("com/my_test/jnidemo/Person");jmethodID personMid = env->GetMethodID(personCls, "<init>", "(ILjava/lang/String;)V");jobject arrayList = env->NewObject(clazz, constructMid);jint i = 0;for (;i<3;i++){jstring name = env->NewStringUTF("Native");jobject person = env->NewObject(personCls, personMid, 18+i, name);env->CallBooleanMethod(arrayList, addMid, person);}return arrayList;
}

2. 动态注册

2.1 步骤

  • 动态注册
  • 先编写Java的native方法
  • 编写JNI函数的实现(函数名可以随便命名)
  • 利用结构体JNINativeMethod保存Java native方法和JNI函数对应关系
  • 利用registerNatives(JNIEnv* env)注册类的所有本地方法
  • 在JNI_OnLoad方法中调用注册方法
  • 在java中通过System.loadLibrary加载完JNI动态库之后,会自动调用JNI_OnLoad函数完成动态注册

2.2 实现代码:

static jstring sayHello(JNIEnv *env, jobject){LOGI("hello, this is native log.");const char *hello = "Hello from c++";return env->NewStringUTF(hello);
}
static JNINativeMethod jni_Methods_table[] = {{"getStringFromCpp", "()Ljava/lang/String;", (void*)sayHello},
};
static int registerNativeMethods(JNIEnv *env, const char *className, const JNINativeMethod *gMethods, int numMethods){jclass clazz;LOGI("Registering %s natives\\n", className);clazz = env->FindClass(className);if (clazz == NULL){LOGE("Native registration unable to find class %s\\n", className);return JNI_ERR;}if (env->RegisterNatives(clazz, gMethods, numMethods) < 0){LOGE("Register natives failed for %s\\n", className);return JNI_ERR;}env->DeleteLocalRef(clazz);return JNI_OK;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{LOGI("call JNI_OnLoad");JNIEnv *env = NULL;if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK){return JNI_EVERSION;}registerNativeMethods(env, className, jni_Methods_table, sizeof(jni_Methods_table)/sizeof(JNINativeMethod));return JNI_VERSION_1_4;
}JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_registerNatives(JNIEnv *env, jclass clazz){env->RegisterNatives(clazz, jni_Methods_table, sizeof(jni_Methods_table)/sizeof(JNINativeMethod));
}
#ifdef __cplusplus
}
#endif

完整代码:
链接
其他可参考文章:
链接
链接