动态注册JNI

来源:互联网 发布:js添加dom节点 编辑:程序博客网 时间:2024/06/05 10:19
 

动态注册JNI

分类: JNI/NDK 5572人阅读 评论(6)收藏 举报
jnijavastringnullfilestruct

在纯java中使用JNI文章中可以看到,javanative方法与C/C++代码函数是通过Java_<包名>_<类名>_<方法名>这种方式对应的,即它是静态注册的。当需要使用现有的C/C++代码函数时,需要以这种形式定义包装函数,在包装函数中调用现有C/C++代码函数;而且这样的函数名也非常长,不适合管理。使用动态注册,可以不受上述命名的限制。

运行下面示例需要安装NDK及搭建环境,请看另一篇文章使用NDK与环境搭建

下面我将Android NDK中的samples\hello-jni示例,由原来的静态注册改为动态注册,只需要改JNI部分。

samples\hello-jni\jni\hello-jni.c的原代码如下

[cpp] view plaincopyprint?
  1. #include <string.h>  
  2. #include <jni.h>  
  3.   
  4. /* This is a trivial JNI example where we use a native method 
  5.  * to return a new VM String. See the corresponding Java source 
  6.  * file located at: 
  7.  * 
  8.  *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java 
  9.  */  
  10. jstring  
  11. Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,  
  12.                                                   jobject thiz )  
  13. {  
  14.     return (*env)->NewStringUTF(env, "Hello from JNI !");  
  15. }  


将其改为

[cpp] view plaincopyprint?
  1. #include <stdlib.h>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4. #include <jni.h>  
  5. #include <assert.h>  
  6.   
  7. /* This is a trivial JNI example where we use a native method 
  8.  * to return a new VM String. See the corresponding Java source 
  9.  * file located at: 
  10.  * 
  11.  *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java 
  12.  */  
  13. jstring native_hello(JNIEnv* env, jobject thiz)  
  14. {  
  15.     return (*env)->NewStringUTF(env, "动态注册JNI");  
  16. }  
  17.   
  18. /** 
  19. * 方法对应表 
  20. */  
  21. static JNINativeMethod gMethods[] = {  
  22.     {"stringFromJNI""()Ljava/lang/String;", (void*)native_hello},//绑定  
  23. };  
  24.   
  25. /* 
  26. * 为某一个类注册本地方法 
  27. */  
  28. static int registerNativeMethods(JNIEnv* env  
  29.         , const char* className  
  30.         , JNINativeMethod* gMethods, int numMethods) {  
  31.     jclass clazz;  
  32.     clazz = (*env)->FindClass(env, className);  
  33.     if (clazz == NULL) {  
  34.         return JNI_FALSE;  
  35.     }  
  36.     if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {  
  37.         return JNI_FALSE;  
  38.     }  
  39.   
  40.     return JNI_TRUE;  
  41. }  
  42.   
  43.   
  44. /* 
  45. * 为所有类注册本地方法 
  46. */  
  47. static int registerNatives(JNIEnv* env) {  
  48.     const char* kClassName = "com/example/hellojni/HelloJni";//指定要注册的类  
  49.     return registerNativeMethods(env, kClassName, gMethods,  
  50.             sizeof(gMethods) / sizeof(gMethods[0]));  
  51. }  
  52.   
  53. /* 
  54. * System.loadLibrary("lib")时调用 
  55. * 如果成功返回JNI版本, 失败返回-1 
  56. */  
  57. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {  
  58.     JNIEnv* env = NULL;  
  59.     jint result = -1;  
  60.   
  61.     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  62.         return -1;  
  63.     }  
  64.     assert(env != NULL);  
  65.   
  66.     if (!registerNatives(env)) {//注册  
  67.         return -1;  
  68.     }  
  69.     //成功  
  70.     result = JNI_VERSION_1_4;  
  71.   
  72.     return result;  
  73. }  

改成动态注册后,当调用HelloJni类的public native String  stringFromJNI()方法时,会找到动态注册的native_hello函数。


上面的代码没什么难点,唯一看不明白的可能是方法对应表,下面来讲讲

JNINativeMethod是JNI机制定义的一个结构体

[cpp] view plaincopyprint?
  1. typedef struct {    
  2. const char* name;  //Java中函数的名字  
  3. const char* signature;  //用字符串描述的函数的参数和返回值  
  4. void* fnPtr;  //指向C函数的函数指针  
  5. } JNINativeMethod;   

比较难以理解的是第二个参数,例如

"()V"

"(II)V"

"(Ljava/lang/String;Ljava/lang/String;)V"


实际上这些字符是与函数的参数类型一一对应的。

"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);


具体的每一个字符的对应关系如下

字符 Java类型 C类型

V      void            void
Z       jboolean     boolean
I        jint              int
J       jlong            long
D      jdouble       double
F      jfloat            float
B      jbyte            byte
C      jchar           char
S      jshort          short


数组则以"["开始,用两个字符表示

[I       jintArray      int[]
[F     jfloatArray    float[]
[B     jbyteArray    byte[]
[C    jcharArray    char[]
[S    jshortArray   short[]
[D    jdoubleArray double[]
[J     jlongArray     long[]
[Z    jbooleanArray boolean[]


上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring

Ljava/lang/String; String jstring
Ljava/net/Socket; Socket jobject


如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁不开口说话怎么办 八个月宝宝断奶不吃奶粉怎么办 宝宝断奶不喝奶粉怎么办 周岁 给娘家东西婆家看见怎么办 自己娘家妈总说婆家人坏话怎么办 娘家婆家老公都没有依靠怎么办? 2岁宝宝断奶粉怎么办 2岁宝宝夜奶频繁怎么办 宝宝15个月还在吃夜奶怎么办 宝宝两岁四个月还吃母乳怎么办 宝宝睡前老是找奶吃怎么办 宝宝戒奶晚上哭怎么办 宝宝戒奶半夜哭怎么办 吸习惯母乳不吸奶嘴怎么办 八个月宝宝奶睡怎么办 宝宝要吸着奶睡怎么办 戒母乳胸胀的疼怎么办 断奶孩子晚上哭的厉害怎么办 喜欢咬指甲的人怎么办? 成年了还咬指甲怎么办 戒奶乳房有硬块怎么办 戒奶七天有硬块怎么办 两岁宝宝喘气粗怎么办 两岁宝宝断不了奶怎么办 两岁宝宝不愿意喝奶粉怎么办 吃母乳不愿意吃奶粉怎么办 母乳宝宝不愿意喝奶粉怎么办 宝宝断母乳不喝奶粉怎么办 9个月宝宝不会爬怎么办 孩子五年级学习成绩差该怎么办 孩子临近中考学习成绩很差该怎么办 初中生成绩不好家长该怎么办 成绩差该怎么办贴吧 宝宝只会匍匐爬怎么办 一年级的孩子数学不好怎么办 小学一年级孩子数学不好怎么办 孩子上一年级数学太差怎么办 智商低情商也低怎么办? 孩子字写得很大怎么办 孩子拿笔重 写字太黑 怎么办 孩子语文成绩好数学不行怎么办?