惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Securelist
O
OpenAI News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News and Events Feed by Topic
S
Security Affairs
SecWiki News
SecWiki News
Project Zero
Project Zero
L
Lohrmann on Cybersecurity
P
Proofpoint News Feed
P
Palo Alto Networks Blog
L
LINUX DO - 最新话题
H
Hacker News: Front Page
Recent Commits to openclaw:main
Recent Commits to openclaw:main
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
W
WeLiveSecurity
T
The Exploit Database - CXSecurity.com
K
Kaspersky official blog
The GitHub Blog
The GitHub Blog
I
InfoQ
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
B
Blog
IT之家
IT之家
AWS News Blog
AWS News Blog
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
Spread Privacy
Spread Privacy
N
News and Events Feed by Topic
Security Latest
Security Latest
美团技术团队
C
Check Point Blog
WordPress大学
WordPress大学
T
Tenable Blog
S
Security @ Cisco Blogs
Last Week in AI
Last Week in AI
博客园 - 聂微东
月光博客
月光博客
博客园 - 【当耐特】
S
Schneier on Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Secure Thoughts
Schneier on Security
Schneier on Security
C
Cisco Blogs
Cyberwarzone
Cyberwarzone

博客园 - 星辰之力

网站工具 Vue项目用于Ios和Android端开发 Android assets文件夹之位置放置和作用 轻松搭建Xposed Hook cordov vue项目中调用手机原生api Android 直接修改dex破解 Android 逆向实战篇(加密数据包破解) Android Studio NDK JNI动态注册本地方法 JNI C反射调用java方法 JNI NDK (AndroidStudio+CMake )实现C C++调用Java代码流程 Jni 线程JNIEnv,JavaVM,JNI_OnLoad(GetEnv返回NULL?FindClass返回NULL?) Jni OnLoad()和OnUnload() Android JNI之C/C++层调用JAVA Android NDK编译之undefined reference to 'JNI_CreateJavaVM' Android 开创java世界(JNI Invocation API) Android JNI c/c++调用java 无需新建虚拟机 cmake:善用find_package()提高效率暨查找JNI支持 如何解决用CMake未定义引用`JNI_CreateJavaVM'? [Linker error] undefined reference to `_imp__JNI_CreateJavaVM@12'
Android JNI中C调用Java方法
星辰之力 · 2019-03-27 · via 博客园 - 星辰之力

背景需求

  我们需要在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(这两个参数一定要加入)来获得,放到第二个参数即可。

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方法在同一个类中