JNI接口
1.使用JNIEXPORT、JNICALL和包名限定native方法,这样jvm在加载so的时候,能够找到对应的成员方法
JNIEXPORT void JNICALL Java_com_midea_xiexb4_nativetest_JniUtil_getStringFromJNI (JNIEnv * env, jobject obj);
如果对包名路径或者参数不熟悉,可以先编写jniUtil类,通过javah为类中使用native声明的方法生成对应的c/c++头文件,帮助native方法编写,这个也是Android官方推荐的方法。
生成方法为在src/java/(注意是具体类所在包名的上级目录)目录下执行javah 包名.类名,如
javah(或者新版本用javac -h) com.midea.xiexb4.nativetest.JniUtil
自动生成com_midea_xiexb4_nativetest_JniUtil.h,将头文件放到native.c的同级目录,包含该头文件后,即可编写具体方法实现。
2.使用JNI_OnLoad函数,注册具体的native方法
jint JNI_OnLoad(JavaVM *jvm, void *reserved)
使用FindClass找到native方法成员所属类名,通过RegisterNatives注册对应的方法列表,列表中通过变量签名表示方法的入参和出参,方法列表定义如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
如
static const JNINativeMethod method_table[]= {
{"init_native","()Z",(void*)flexcan_init},
{"flexcan_native_send","([IIIIIII)I",(void*)flexcan_native_send},
{"flexcan_native_dump","(IILcom/android/server/Frame;)Lcom/android/server/Frame;",(void*)flexcan_native_dump},
};
**注意:**如果RegisterNatives函数返回失败,很有可能是方法表中的形参或者返回结果,与java类中声明的native函数成员不一致。
类型 相应的签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
boject L+用/分隔包的完整类名 +; 如Ljava/lang/String;
Array [签名 如: [B 或者 [Ljava/lang/Object;
Method (参数1类型签名 参数2类型签名…)返回值类型签名
3.native编程中需要注意的事项
3.1 Java与Jni中的数据类型对照表
Java类型 JNI 定义的别名
int jint/jsize
long jlong
byte jbyte
boolean jboolean
char jchar
short jshort
float jfloat
double jdouble
object jobject
3.2 C与C++的区别
比如对于入参JNIEnv *env, 在jni.h中有定义
struct JNINativeInterface_;
struct JNIEnv_;
#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif
所以在C++中有
env->FindClass("java/lang/String");
在C中有
(*env)->FindClass(env, "java/lang/String")
3.3 类变量的获取、修改,成员方法的调用
//调用类的成员方法
jclass frame_cls = env->FindClass("com/android/server/Frame");
jmethodID setID = env->GetMethodID(frame_cls, "setID","(I)V");//获取名为setID,入参为int,出参为void的成员方法
env->CallVoidMethod(myFrame,setID,can_id);
//修改类的成员变量
jclass class_Test=env->GetObjectClass(obj);
jfieldID fid_msg=env->GetFieldID(class_Test,"message","I"); //获取名为message,类型为int的成员
env->SetIntField(obj,fid_msg,123); //修改变量为123
4 jni库的重命名
直接修改CMakeList.txt中的add_library和target_link_libraries属性即可