参考:http://blog.csdn.net/qinjuning/article/details/7607214
1、动态加载函数
static JNINativeMethod gMethods[] = { {"chargerhdVersion", "()Ljava/lang/String;", (void *) jni_chargerhdVersion}, {"setLedState", "(III)V", (void *) jni_setLedState}, {"chargerhdInit","()V",(void*)jni_chargerhdInit}, {"chargerhdUnInit","()V",(void*)jni_chargerhdUnInit}, }; int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) { jclass clazz; clazz = env->FindClass(className); if (clazz == NULL) { return JNI_FALSE; } if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } int registerNatives(JNIEnv *env) { const char *kClassName = CLASS_NAME;//指定要注册的类 return registerNativeMethods(env, kClassName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { g_vm = vm; JNIEnv *env = NULL; jint result = -1; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return -1; } assert(env != NULL); if (!registerNatives(env)) {//注册 return -1; } //成功 result = JNI_VERSION_1_6; return result; }2、回调java接口
jint android::updateMeter(MeterInfo info) { //使用namespace括起来,供外部C调用 bool isAttacked = false; jint javaIndex = -1; JNIEnv *env = NULL; int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6); if (status < 0) { status = g_vm->AttachCurrentThread(&env, NULL); if (status < 0) { return -1; } isAttacked = true; } jclass clz = env->GetObjectClass(g_object);//获取加载.so的类 (g_object = env->NewGlobalRef(thiz);) //获取函数id jmethodID mid = env->GetMethodID(clz, "onMeterInfoChanged", "(Lcom/huliuda/rocky/MeterInfo;)V"); if (mid) { jmethodID id = env->GetMethodID(g_jclass_meter,"<init>","()V");//获取构造函数 jobject meter = env->NewObject(g_jclass_meter,id);//获取实例 env->CallIntMethod(g_object, mid, meter); env->DeleteLocalRef(clz); env->DeleteLocalRef(meter); } if(isAttacked) { g_vm->DetachCurrentThread(); } return javaIndex; }
3、坑1:
在添加回调java层方法时,如果调用下面jni_chargerhdInit的java层方法,就能使用其中的"thiz"来创建jobject和jclass,否则会找不到准确的类和对象。
void jni_chargerhdInit(JNIEnv *env, jobject thiz){ g_object = env->NewGlobalRef(thiz); g_jclass_meter = env->FindClass("com/atsmart/chargerhdservice/MeterInfo"); g_jclass_meter = (jclass)env->NewGlobalRef(g_jclass_meter); monitor = new MeterMonitor(); }4、坑2:
在回调自定义的java层对象时,需要先在主线程中预加载类,如上图
g_jclass_meter = env->FindClass("com/atsmart/chargerhdservice/MeterInfo");
然后调用如下:
jint android::updateMeter(MeterInfo info) { bool isAttacked = false; jint javaIndex = -1; JNIEnv *env = NULL; int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6); if (status < 0) { status = g_vm->AttachCurrentThread(&env, NULL); if (status < 0) { return -1; } isAttacked = true; } jclass clz = env->GetObjectClass(g_object); //获取函数id jmethodID mid = env->GetMethodID(clz, "onMeterInfoChanged", "(Lcom/huliuda/rocky/MeterInfo;)V"); if (mid) { jmethodID id = env->GetMethodID(g_jclass_meter,"<init>","()V"); jobject meter = env->NewObject(g_jclass_meter,id); env->CallIntMethod(g_object, mid, meter); env->DeleteLocalRef(clz); env->DeleteLocalRef(meter); } if(isAttacked) { g_vm->DetachCurrentThread(); } return javaIndex;}
==============================================================1、constant char* 转String// 定义java String类 strClass jclass strClass = env->FindClass("java/lang/String");//注意不是"Ljava/lang/String",否则报错 // 获取java String类方法String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); // 建立byte数组 jbyteArray bytes = env->NewByteArray((jsize)strlen(msg)); // 将char* 转换为byte数组 env->SetByteArrayRegion(bytes, 0, (jsize)strlen(msg), (jbyte*)msg); //设置String, 保存语言类型,用于byte数组转换至String时的参数 jstring encoding = (env)->NewStringUTF("GB2312"); //将byte数组转换为java String,并输出 jstring msg = (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);