JNI C/C++ Callback from JAVA
Posted 跨链技术践行者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI C/C++ Callback from JAVA相关的知识,希望对你有一定的参考价值。
JNI
是 JAVA
世界和底层世界沟通的重要桥梁,在android
的底层开发中用到的较多。相关知识在网络上也容易搜索到,这里也不再累述。
本篇文章,要介绍的是,在Java通过JNI传递一个callback函数到C/C++中。
JAVA层
首先你需要有个callback 的类:
public interface BLDeviceInfoCallback
String deviceInfo(String did, String name, boolean state);
然呢在你提供生成JNI的JAVA类里面,添加相应的native函数:
可以使用javah生成相应的jni的.h文件,类似于
NIEXPORT void JNICALL Java_cn_com_broadlink_vtbridge_VtBridegeApi_setBlDeviceInfoCallback(JNIEnv *, jobject, jobject)
C/C++层
根据刚才生成的jni .h文件,我们再去实现相应的接口:
static JavaVM *gJavaVM;
static jobject gInfoObject;
static jmethodID gInfoMethodID;
JNIEXPORT void JNICALL Java_cn_com_broadlink_vtbridge_VtBridegeApi_setBlDeviceInfoCallback(JNIEnv *env, jobject thiz, jobject jCallback)
if (gJavaVM == NULL)
(*env)->GetJavaVM(env, &gJavaVM);
if (gJavaVM == NULL)
loge("Get gJavaVM is NULL");
return;
gInfoObject = (*env)->NewGlobalRef(env, jCallback);
if (gInfoObject == NULL)
loge("Get gInfoObject failed");
return;
jclass infoClass = (*env)->GetObjectClass(env, jCallback);
if (infoClass == NULL)
loge("Get infoClass failed");
return;
gInfoMethodID = (*env)->GetMethodID(env, infoClass, "deviceInfo", "(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;");
if (gInfoMethodID == 0 )
loge("Cannot find method:vtDeviceControl");
return;
如上就将JAVA函数映射到了C里面,但是由于env 环境是线程不安全的,所以我们获取了唯一JavaVM 虚拟机来实现线程中调用相应类和方法。
static JNIEnv *Adapter_GetEnv()
int status;
JNIEnv *envnow = NULL;
if (gJavaVM == NULL)
loge("JavaVM is NULL");
return NULL;
status = (*gJavaVM)->GetEnv(gJavaVM,(void **)&envnow, JNI_VERSION_1_4);
if(status < 0)
status = (*gJavaVM)->AttachCurrentThread(gJavaVM, &envnow, NULL);
if(status < 0)
return NULL;
g_bAttatedT = true;
return envnow;
static void DetachCurrent()
if(g_bAttatedT)
(*gJavaVM)->DetachCurrentThread(gJavaVM);
然后实现C函数,根据上述获取到的JAVA虚拟机,类ID和方法ID,来调用JAVA层实现的函数
int vtbridge_device_info(unsigned char *did, unsigned char *name, bool state, unsigned char *output, int outLen)
char *cstr = NULL;
if (NULL == did || NULL == name || NULL == output)
loge("vtbridge_device_info input error");
return -1;
JNIEnv *env = Adapter_GetEnv();
if (env)
jstring jDid = (*env)->NewStringUTF(env, (const char *)did);
jstring jName = (*env)->NewStringUTF(env, (const char *)name);
jstring jresult = (*env)->CallObjectMethod(env, gInfoObject, gInfoMethodID, jDid, jName, state);
cstr = (char *)(*env)->GetStringUTFChars(env, jresult, 0);
strncpy(output, cstr, outLen);
if (NULL != cstr)
(*env)->ReleaseStringUTFChars(env, jresult, cstr);
DetachCurrent();
return 0;
return -1;
至此在提供的JNI库中就完成了C调用JAVA callback函数的工作,而在应用层中,只需要在相应的代码中实现
public interface BLDeviceInfoCallback
String deviceInfo(String did, String name, boolean state);
就可以了。
注意事项:
1. GetMethodID CallXXXXMethod 以及 GetStaticMethodID CallStaticXXXXMethod 需要根据实际的JAVA方法进行区分,由于在老版本Android平台上上述方法区分不明显,所以可能导致在老版本Android上跑的正常,而到了新版本Android平台上则报错;
2. 同样由于有些方法是类方法,有些是实例方法,所以在调用CallXXXXMethod和CallStaticXXXXMethod,需要区分清楚具体的参数是jclass还是jobject;
以上是关于JNI C/C++ Callback from JAVA的主要内容,如果未能解决你的问题,请参考以下文章
JNI/NDK开发指南——C/C++访问Java实例方法和静态方法