一、什么是jni
JNI java native interface native本地 java本地接口
通过JNI可以实现java和本地代码之间相互调用
jni可以看做是翻译 实际上就是一套协议
二、如何使用jni调用c的方法
这个比较简单,先生命native 方法
public native String stringFromJNI();
三、如何在c层调用java的方法
Android开发中一般讲Java接口调用放在APP层,但是如果想对外隐藏Java接口调用,应该怎么办呢?我们可以将接口调用放在JNI层,通过反射调用所需接口,之后打包成.so库,这样既可对外隐藏所有调用细节。下面开始讲解JNI怎么调用Java方法
1.生成测试类的class文件
package com.thomas;
import android.util.Log;
/**
* Author:yangzhikuan
* Date:2020-08-31
* Description:JNITestClass
*/
public class JNITestClass {
private final static String TAG = "JNITestClass";
public JNITestClass(){
Log.i(TAG, "JNITestClass");
}
public void test(int index) {
Log.i(TAG, "test : " + index);
}
public static void testStatic(String str) {
Log.i(TAG, "testStatic : " + str);
}
public static class InnerClass {
private int num;
public InnerClass() {
Log.i(TAG, "InnerClass");
}
public void setInt(int n) {
num = n;
Log.i(TAG, "setInt: num = " + num);
}
}
}
2.进入class文件目录查看方法签名
这里首先Make Project,否则不会生成Java文件对应的class文件
进入到classpath目录下:
命令: cd app/build/intermediates/classes/debug
查看外部类的签名
javap -s -p JNITestClass
查看内部类的签名
javap -s -p JNITestClass$InnerClass
3.c代码中调用
JNIEXPORT void JNICALL Java_com_thomas_MainActivity_JNIReflect
(JNIEnv *env, jobject thiz)
{
//实例化Test类
jclass testclass = (*env)->FindClass(env, "com/thomas/JNITestClass");
//构造函数的方法名为
jmethodID testcontruct = (*env)->GetMethodID(env, testclass, "", "()V");
//根据构造函数实例化对象
jobject testobject = (*env)->NewObject(env, testclass, testcontruct);
![4EA2504C-7B3C-47EC-8D94-C6407D52131E.png](https://upload-images.jianshu.io/upload_images/9005980-72d764afa7531b67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
//调用成员方法,需使用jobject对象
jmethodID test = (*env)->GetMethodID(env, testclass, "test", "(I)V");
(*env)->CallVoidMethod(env, testobject, test, 1);
//调用静态方法
jmethodID testStatic = (*env)->GetStaticMethodID(env, testclass, "testStatic", "(Ljava/lang/String;)V");
//创建字符串,不能在CallStaticVoidMethod中直接使用"hello world!",会报错的
jstring str = (*env)->NewStringUTF(env, "hello world!");
//调用静态方法使用的是jclass,而不是jobject
(*env)->CallStaticVoidMethod(env, testclass, testStatic, str);
//实例化InnerClass子类
jclass innerclass = (*env)->FindClass(env, "com/thomas/JNITestClass$InnerClass");
jmethodID innercontruct = (*env)->GetMethodID(env, innerclass, "", "()V");
jobject innerobject = (*env)->NewObject(env, innerclass, innercontruct);
//调用子类的成员方法
jmethodID setInt = (*env)->GetMethodID(env, innerclass, "setInt", "(I)V");
(*env)->CallVoidMethod(env, innerobject, setInt, 2);
}
//调用成员方法
jmethodID testcontruct = (*env)->GetMethodID(env, testclass, "", "()V");
//调用静态方法
jmethodID testStatic = (*env)->GetStaticMethodID(env, testclass, "testStatic", "(Ljava/lang/String;)V");
注意:最后一个参数需要穿对应的签名