JNI开发技术归纳

来源:互联网 发布:网络诈骗罪到哪里报警 编辑:程序博客网 时间:2024/06/04 15:58
0.JNI概述

      在Android开发中会遇到使用JNI的情况,JNI是Java Native Interface的缩写,即Java本地接口,通过JNI技术可以实现两点:

      1)Java程序能够调用Native函数,Native一般指的是C/C++

      2)Native函数能够调用Java层的方法

1.JNI注册
      JNI的注册分成两种:1)静态注册;2)动态注册
      Java层实现调用Native函数的代码示例如下:
public class JniHelper{    static {         System.loadLibrary("jni_helper");    }    private static native void nativeFunc();}

      其中jni_helper是jni层库libjni_helper.so去掉lib后的名字,是由程序运行时系统加载,带有native关键字的方法,说明此方法是native代码实现的,也就是说该方法在库libjni_helper.so中实现

      所谓的注册,也就是将java层中的nativeFunc()对应到libjni_helper.so库中的实现上,将声明和实现联系起来

      1)静态注册的流程一般是,先编写java层代码,将java代码编译成class文件,再使用java提供的javah工具生成一个JNI层头文件,例如:javah -o jni_helper packgename.JniHelper,packgename.JniHelper是class文件,生成一个名为jni_helper.h的头文件,其中Java层声明的nativefunc()方法在JNI头文件中会声明为
      JNIEXPORT void JNICALL Java_pack_age_name_JniHelper_nativeFunc(JNIEnv*, jclass);
      之所以将packagename写成pack_age_name,是因为包名中的"."会转换成"_",此处仅作示例
      最后,根据这个生成的JNI层头文件,对应实现native方法就可以了,在Java层调用Native函数的时候,系统会到JNI库libjni_helper.so中去找对应的方法,找到的话就会为Java层方法和库中的方法(即JNI头文件中那一长串的方法声明)建立起关联,这就是静态注册的方式
      2)实际上android中大都用的是动态注册方式,这种方式下会用到一个结构体JNINativeMethod,在JNI层代码中会定义一个JNINativeMethod数组

       static JNINativeMethod gMethod[] = {      {        "nativeFunc", //Java层方法声明        "()V", //函数签名        (void *)nativeFFFunc //JNI层对应的函数指针      }      };

      对应的注册函数如下:

int registerNativeMethod(JNIEnv * env, const char * className, const JNINativeMethod * gMethod, int numMethods){     jclass clazz;     clazz = (*env)->FindClass(env, className);          if((*env)->RegisterNatives(env, clazz, gMethods, numMethods)<0)     {        return -1;     }     return 0;}

      调用JNIEnv的RegisterNatives函数,就能够动态注册这种Java层函数与Native函数的关联

      最后还需要实现JNI_Onload函数,该函数在JNI库libjni_helper.so加载时会去调用,如果实现了该函数,则调用它,没有实现则略过,当然在静态注册的时候也可以实现该函数,完成一些初始化工作,JNI_Onload函数示例如下:

jint JNI_Onload(JavaVM* vm, void* reserved){      JNIEnv* env = NULL;      jint result = -1;            if(vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK)      {              return result;      }      //动态注册JNI函数,className指明Java中的类,形如"com/example/JniHelper",包的"."由"/"代替      registerNativeMethod(JNIEnv* env, const char* className, const JNINativeMethod* gMethod, int numMethods);           return JNI_VERSION_1_4; //这个必须有,否则会报错}
2.数据类型转换

      Java数据类型分为基本数据类型和引用数据类型两种

      1)基本数据类型转换如下:

JavaNative符号位数booleanjboolean无符号8位bytejbyte无符号8位charjchar无符号16位shortjshort有符号16位intjint有符号32位longjlong有符号64位floatjfloat有符号32位doublejdouble有符号64位











      2)引用数据类型转换如下:

JavaNativejava.lang.Classjclassjava.lang.Stringjstringjava.lang.Throwablejthrowable其他的ObjectjobjectObject[]jobjectArrayboolean[]jbooleanArraybyte[]jbyteArraychar[]jcharArrayshort[]jshortArrayint[]jintArraylong[]jlongArrayfloat[]jfloatArraydouble[]jdoubleArray

3.JNI类型签名

      因为Java有函数重载的概念,所以单靠函数名不能区分函数,需要有签名,签名由参数类型和返回值组成,签名格式:

      (参数1类型标识参数2类型标识......参数n类型标识)返回值类型标识

      类型标识表:

Java类型类型标识booleanZbyte BcharCshortSintIlongJfloatFdoubleDStringL/java/langaugeString;int[][IObject[][L/java/lang/object;      数组类型前面会有一个"[",引用类型最后有一个";",签名示例如下:

      String f() 的签名是()Ljava/lang/String;

      int f(char c, int i)的签名是(CI)I 

      签名写起来麻烦,看起来也别扭,不过java有一个javap工具能帮我们生成签名信息,用法如:javap -s -p classfile, classfile是编译后的class文件,-s输出内部数据类型的签名信息,-p打印所有函数和成员的签名信息

0 0
原创粉丝点击