JNI中C调用Java方法
  M9aMEIE19lAW 2023年11月02日 29 0


背景需求

  我们需要在JNI的C代码调用Java代码。实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用。

JNI关键方法讲解。

1. 在同一个类中,调用其他方法






JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1
  (JNIEnv * env, jobject obj){
    //在c代码里面调用java代码里面的方法
    // java 反射
    //1 . 找到java代码的 class文件
    //    jclass      (*FindClass)(JNIEnv*, const char*);
    jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
    if(dpclazz==0){
        LOGI("find class error");
        return;
    }
    LOGI("find class ");

    //2 寻找class里面的方法
    //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
    if(method1==0){
        LOGI("find method1 error");
        return;
    }
    LOGI("find method1 ");
    //3 .调用这个方法
    //    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallVoidMethod(env,obj,method1);
}






javap -p -s(这两个参数一定要加入)来获得,放到第二个参数即可。

JNI中C调用Java方法_Java

注意:

1. 要加入上面的参数 -p -s

2. signature后面有时候带“;”,不要丢掉。 主要要仔细检查

示例:






void notifyOnStatusReport(int32_t status)
{
    if (curEnv != NULL && curObj != NULL) {
        jclass clsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/LiveNativeSender");
        jfieldID mUsercommandCallbackEventListnerFieldId = curEnv->GetFieldID(clsstring,"mStatusEventListener","Lcom/baidu/tieba/liveSdk/publisher/OnStatusEventListener;");
        jobject mUsercommandCallbackEventListner = curEnv->GetObjectField(curObj,mUsercommandCallbackEventListnerFieldId);
        
        jclass onStatusEventListenerClsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/OnStatusEventListener");
        jmethodID onStatusReport = curEnv->GetMethodID(onStatusEventListenerClsstring, "onStatusReport",
                                         "(I)V");
        curEnv->CallVoidMethod(mUsercommandCallbackEventListner, onStatusReport, status);
    }
}






 

这样就可以调用DataProvider中的helloFromJava方法了。

2. 上面的方法是调用的返回值为void的java方法。如果想调用其他类型的。JNI中还提供的许多其他返回类型的方法。






jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
    jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jobject     (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jboolean    (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
    jboolean    (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jboolean    (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
    jbyte       (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jbyte       (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jchar       (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
    jchar       (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jchar       (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jshort      (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
    jshort      (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jshort      (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    jint        (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jint        (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jlong       (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
    jlong       (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    jlong       (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
    jfloat      (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
    jfloat      (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
    jfloat      (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
    jdouble     (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
    jdouble     (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
    jdouble     (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    void        (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
    void        (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);






 

3. 如果java中的方法是静态的,就需要调用GetStaticMethodID 和 CallStaticVoidMethod 方法。






JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod4
  (JNIEnv * env, jobject obj){
      //1 . 找到java代码的 class文件
        //    jclass      (*FindClass)(JNIEnv*, const char*);
        jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
        if(dpclazz==0){
            LOGI("find class error");
            return;
        }
        LOGI("find class ");

        //2 寻找class里面的方法
        //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        // 注意 :如果要寻找的方法是静态的方法 那就不能直接去获取methodid
        //jmethodID method4 = (*env)->GetMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V");
        //    jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID method4 = (*env)->GetStaticMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V");
        if(method4==0){
            LOGI("find method4 error");
            return;
        }
        LOGI("find method4 ");

        //3.调用一个静态的java方法
        //    void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
        (*env)->CallStaticVoidMethod(env,dpclazz,method4,(*env)->NewStringUTF(env,"static haha in c"));
}






 

4. 如果C调用的Java方法不在一个类中。

分析:JNI提供的方法都有两个参数:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上线文。下面的例子的obj不是所需要的上下午,所以要重新创建。

 






//obj DemoActivity
 JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DemoActivity_call_1dp_1method1
  (JNIEnv * env, jobject obj){
    //在c代码里面调用java代码里面的方法
        // java 反射
        //1 . 找到java代码的 class文件
        //    jclass      (*FindClass)(JNIEnv*, const char*);
        jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
        if(dpclazz==0){
            LOGI("find class error");
            return;
        }
        LOGI("find class ");

        //2 寻找class里面的方法
        //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
        if(method1==0){
            LOGI("find method1 error");
            return;
        }
        LOGI("find method1 ");
        //3 .调用这个方法
        //    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        //    jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
        //  jobject     (*AllocObject)(JNIEnv*, jclass);
        jobject dpobj= (*env)->AllocObject(env,dpclazz);

        (*env)->CallVoidMethod(env,dpobj,method1);
}






 

5. 提示

为了避免4中的内容,我们尽量让C要调用的Java方法在同一个类中





【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  UP4ONKOBnkdD   2023年11月28日   28   0   0 java
  9JCEeX0Eg8g4   2023年12月10日   31   0   0 应用程序javaApache
  KRsXEGSB49bk   2023年11月27日   30   0   0 javaApache
  YKMEHzdP8aoh   2023年12月11日   67   0   0 DNSidePod
  YKMEHzdP8aoh   2023年11月24日   37   0   0 ide重定向Rust