so library calls java method

Tip: After the article is written, the table of contents can be automatically generated. For how to generate it, please refer to the help document on the right.

Article directory


Preface

The process of JNI calling Java methods is to first find the class through the class name, then find the method id according to the method name, and finally call the method. If you are calling a non-static method in Java, you need to construct an object of the class before you can call it. The following example demonstrates how to call Java's static methods , as well as non-static methods in JNI .

Operating procedures

Create a new JniTest class, the code is as follows

public class JniTest {
    
    
    static {
    
    
        System.loadLibrary("jni-test");  //加载libjni-test.so库
    }

    public native String callJniMethod();  //声明本地方法,调用so库代码

    public static void staticMethodCalledByJni(String msgFromJni) {
    
        //静态方法
        Log.d("test","staticMethodCalledByJni,msg:" + msgFromJni);
    }

    public String methodCalledByJni(String msgFromJni) {
    
       //非静态方法
        Log.d("test","methodCalledByJni,msg:" + msgFromJni);
        return "methodCalledByJni!!!";
    }
}

Implement the callJniMethod method in JNI and call the static and non-static methods defined above. Create a new jni folder in the project
app directory, and create the test.c file in the jni folder. The code is as follows:

#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <android/log.h>

void
callJavaStaticMethod(JNIEnv *env, jobject thiz) {
    
    
     //1. 获取JniTest类的Class引用
    jclass clazz = (*env)->FindClass(env,"com/habit/jnitest/JniTest");
    if (clazz == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "find class JniTest error!\n");
        return;
    }
    //2.获取JniTest类的staticMethodCalledByJni方法的id
    jmethodID id = (*env)->GetStaticMethodID(env,clazz, "staticMethodCalledByJni", "(Ljava/lang/String;)V");
    if (id == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "find method staticMethodCalledByJni error!\n");
    }
    jstring msg = (*env)->NewStringUTF(env,"msg send by callJavaStaticMethod in test.c.");
    //3.调用java的staticMethodCalledByJni方法
    (*env)->CallStaticVoidMethod(env,clazz, id, msg);
}

jstring
callJavaMethod(JNIEnv *env, jobject thiz) {
    
    
     //1. 获取JniTest类的Class引用
    jclass clazz = (*env)->FindClass(env,"com/habit/jnitest/JniTest");
    if (clazz == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "find class JniTest error!\n");
        return "";
    }
    //2. 获取类的默认构造函数ID
    jmethodID construct_id = (*env)->GetMethodID(env,clazz, "<init>", "()V");
    if (construct_id == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "find method construct_id error!\n");
    }
    //3.实例化这个对象
    jobject jobj = (*env)->NewObject(env,clazz, construct_id);
    if (jobj == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "NewObject jobj error!\n");
    }
    //4.获取JniTest类的methodCalledByJni方法的id
    jmethodID id = (*env)->GetMethodID(env,clazz, "methodCalledByJni", "(Ljava/lang/String;)Ljava/lang/String;");
    if (id == NULL) {
    
    
        __android_log_print(ANDROID_LOG_ERROR, "test", "find method methodCalledByJni error!\n");
    }
    jstring msg = (*env)->NewStringUTF(env,"msg send by callJavaMethod in test.c.");
    //5.调用java的methodCalledByJni方法
    return (jstring)(*env)->CallObjectMethod(env,jobj, id, msg);
}

jstring
Java_com_habit_jnitest_JniTest_callJniMethod(JNIEnv *env, jobject thiz) {
    
    
    //调用静态方法
    callJavaStaticMethod(env,thiz);
    //调用非静态方法
    jstring str = callJavaMethod(env,thiz);
    char* str2 = (char*) (*env)->GetStringUTFChars(env,str, 0); //string 转char*
     __android_log_print(ANDROID_LOG_ERROR, "test", "%s\n",str2);
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

Remarks:
(1) One of the parameters of the FindClass method is "package name/class name", which should be changed to your own package name and class name.
(2) The method name corresponding to java in jni is Java_package name_class name_method name. Java_com_habit_jnitest_JniTest_callJniMethod in the code below should be changed to the package name of your own project.

Create the Android.mk file in the jni folder. The file content is as follows:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#加入这句可以使得so文件打印日志
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog

#生成so库的名称,生成后会添加前缀lib
LOCAL_MODULE    	:= jni-test
LOCAL_SRC_FILES		:= test.c

include $(BUILD_SHARED_LIBRARY)

Generate the so library and cut the so library to the app\src\main\jniLibs folder.

Insert image description here

For the steps to generate so library, please refer to AndroidStudio to generate so library.

Call the so library method in MainActivity, the code is as follows:

public class MainActivity extends AppCompatActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JniTest jniTest = new JniTest();
        System.out.println(jniTest.callJniMethod());
    }
}

Run the program. The log of normal operation of the program is as follows:
Insert image description here


Guess you like

Origin blog.csdn.net/weixin_46092051/article/details/131653138