1.JNI 概述
JNIEnv 指代 java 本地接口环境(java native interface environment),是一个 JNI 接口指针,指向本地方法的一个函数表,该函数表中的每一个成员指向了一个 JNI 函数,本地方法通过 JNI 函数来访问 JVM 中的数据结构,结构如图:
2.概念解释
2.1 jobject 和 jclass
Jobject 与 jclass 通常作为 JNI 函数的第二个参数,当所声明的 native 方法是静态方法时,对应参数 jclass,因为静态方法不依赖对象实例,而依赖于类,所以参数中传递的是一个 jclass类型。如果声明的 native 方法为非静态时,对应的参数是 jobject。
为了在 native 层访问 java 中的类和对象,jobject 和 jclass 分别指代了其所指代的对象和类,进而访问成员方法和成员变量等。我们一般使用 javah 指令直接生成 native 函数的函数原型,故而不必纠结该使用哪种类型。
在 jni.h 文件中查看 jcalss 和 jobject 在 C++ 语境中的定义:
class _jobject {};
class _jclass : public _jobject {};
typedef _jobject* jobject;
typedef _jclass* jclass;
2.2 方法介绍
2.3 数据类型
(1)基本数据类型
基本数据类型之间可以直接转换。
(2)字符串类型
字符串类型需要专门的转换函数。
static std::string jstring2cstring(JNIEnv *env, jstring jstr);
static jstring cstring2jstring(JNIEnv *env, const std::string& cstr);
3.调用 java 函数
java 接口
xxx.java
public interface Observer {
void onFirstFrameRender(int hash);
void onErrorOccured(int error, String reason, int hash);
void onFrameRateCallback(int frameCoundPerSecond, int errorFrameCountPerSecond, int avaliableFrameCountPerSecond, int hash);
}
xxx.cpp
std::map<jint, jobject> g_observer_map;
void OnErrorOccured(int error, const std::string& reason, int hash) {
JNIEnv *env;
bool mNeedDetach;
int getEnvStat = (*g_VM).GetEnv((void **) &env,JNI_VERSION_1_6);
if (getEnvStat == JNI_EDETACHED) {
if ((*g_VM).AttachCurrentThread(&env, NULL) != 0) {
return;
}
mNeedDetach = JNI_TRUE;
}
auto it = g_observer_map.find(hash);
if (it == g_observer_map.end()) {
return;
}
jobject observer = it->second;
if (observer == NULL) {
return;
}
jclass javaClass = (*env).GetObjectClass(observer);
if (javaClass == 0) {
// LOG("Unable to find class");
return;
}
jmethodID javaCallbackId = (*env).GetMethodID(javaClass,
"onErrorOccured", "(ILjava/lang/String;I)V");
if (javaCallbackId == NULL) {
(*g_VM).DetachCurrentThread();
return;
}
(*env).CallVoidMethod(observer, javaCallbackId, error, sw::jni::cstring2jstring(env, reason));
if(mNeedDetach) {
(*g_VM).DetachCurrentThread();
}
env = NULL;
}
4.小结
接触 JNI 出于临时项目维护的需要,目前只了解了非常浅显的一些皮毛,后续会不断根据遇到的问题来更新完善这篇文档。