总结一下 C 如何 通过 JNI 层调用 Java 的静态和非静态方法

对于:JNIEXPORT void JNICALL Java_com_example_TestNative_sayHello(JNIEnv * env, jobject thiz, jstring paramString)这样一个函数 固定参数: JNIEnv *env:JNIEnv代表java环境,通过*env这个指针,就可以让我们对java层的代码进行操作,比如创建java类的对象,调用java对象的方法,获取java对象的属性等等 这个指针会被JNI传递到本地方法的实现函数中来对java端的代码进行操作。 jobject thiz:分配给这个类的类加载器 函数参数: jstring paramString:这是sayHello函数的具体参数,在外部调用的时候必须给sayHello函数一个参数,如:sayHello(“Hello JNI”); 调用java过程中(重点是调用java中的某些类的某些方法) 主要分下面几个步骤: 1.获取jclass JNIEnv类中有如下几个简单的函数可以取得jclass      jclass FindClass(const char* clsName)  根据类名来查找一个类,完整类名     jclass GetObjectClass(jobject obj)   根据一个对象,获取该对象的类     jclass GetSuperClass(jclass obj)     获取一个类的父类 FindClass:根据类名来查找,需要注意的是:这里的类名是某个类的完整路径。 如:String这个类    jclass cls_string= (*env)->FindClass(“java/lang/String”); 在用的时候 需要把 . 换成 /  2.获取类中方法的ID或类属性的ID JNI在jni.h头文件中定义了 jmethodID和 jfieldID类表示Java端的方法和属性 JNIEnv获取相应的jmethodID和 fieldID 的方法: GetMethodID/GetStaticMethodID   获取一个实例的方法ID/一个静态的方法ID GetFieldID/GetStaticMethodID         获取一个实例的域的ID/一个静态的域的ID GetMethodID原型: jmethodID (JNICALL *GetMethodID)       (JNIEnv *env, jclass clazz, const char *name, const char *sig); 第一个参数默认的*env 第二个参数是获取到的类 第三个参数是你要获取的某一个方法的名字 第四个参数是“签名”,引用这个签名的作用是对这一函数参数和返回值的描述,对于同一个函数,java是允许对它进行重载的,这时候就必须引入签名来区分他们3.调用方法 JNI同样提供了调用java方法的函数 JNIEnv去调用相应java方法的方法有: CallMethod/CallStaticMethod  这里的是要调用的那个方法的返回值类型 大致有 CallVoidMethod                   CallStaticVoidMethod CallIntMethod                     CallStaticIntMethod CallBooleanMethod              CallStaticBooleanMethod CallByteMethod                   CallStaticByteMethod 如:(*env)->CallVoidMethod(env, obj, jm_id,  parameter); 参数一 默认的*env 参数二是获取到的类 参数三是要调用的方法的ID 参数四这一方法的参数 方法的签名: 形如:(参数1类型签名参数2类型签名……参数n类型签名)返回值类型签名 签名分两部分:参数 & 返回值 类型的表述方式有如下对应关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 类型            相应的签名 boolean          Z byte            B char            C short            S int              I long            J float            F double          D void            V object          L/分隔包的完整类名:    Ljava / lang / String ; Array            [签名            [ I        [ Ljava / lang / Object ; Method          (参数 1类型签名 参数 2类型签名··· )返回值类型签名

 

注: 1.object类型的每一个参数最后都得加上”;“ 2.方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则 例如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为”Lcom /nedu/jni/helloword/Student;” 3.方法参数或者返回值为数组类型时,请前加上[ 例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[ 实例: C
1 2 3 4 5 6 void f1 ( )                          ( ) V int f2 ( int , long )                  ( IJ ) I boolean f3 ( int [ ] )                  ( [ I ) B double f4 ( String , int )              ( Ljava / lang / String ; I ) D void f5 ( int , String [ ] , char )      ( I [ Ljava / lang / String ; C ) V byte [ ] f6 ( int , String , String )    ( ILjava / lang / String ; Ljava / lang / String ) [ B
下面以几个实例来重点介绍下方法的签名的书写方式 a、调用某一个类的构造函数: Java
1 2 3 4 5 6 7 8 SecureRandom localSecureRandom = new SecureRandom ( ) ; //获取类: jclass jc_SecureRandom = ( * env ) -> FindClass ( env , "java/security/SecureRandom" ) ; //获取构造函数的ID,构造函数的名称都是“”; //签名:形如"()V"  括号里是参数类型,括号外是返回值类型,这里无参数,返回值是Void jmethodID jm_constructor = ( * env ) -> GetMethodID ( env , jc_SecureRandom , "" , "()V" ) ; //调用: jobject jo_SecureRandom = ( * env ) -> NewObject ( env , jc_SecureRandom , jm_constructor ) ;

 

b、调用String类的getBytes方法: Java
1 2 3 4 5 6 7 8 9 //获取类: jclass jc_string = ( * env ) -> FindClass ( env , "java/lang/String" ) ; //获取方法ID: jmethodID jm_getBytes =      ( * env ) -> GetMethodID ( env , jc_string , "getBytes" , "()[B" ) ; //参数为空,返回值为byte[] //调用: jbyteArray jb_paramString =      ( jbyteArray ) ( * env ) -> CallObjectMethod ( env , paramString , jm_getBytes ) ;

 

c、调用Cipher类的 getInstance方法:
1 2 3 4 5 6 7 8 9 10 11 //获取类: jclass jc_Cipher = ( * env ) -> FindClass ( env , "javax/crypto/Cipher" ) ; //获取方法ID: jmethodID jm_Cipher_getInstance =      ( * env ) -> GetStaticMethodID ( env , jc_Cipher , "getInstance" ,      "(Ljava/lang/String;)Ljavax/crypto/Cipher;" ) ;    //参数是一个string, 返回值是一个Cipher //调用: jobject jo_Cipher =      ( * env ) -> CallStaticObjectMethod ( env , jc_Cipher , jm_Cipher_getInstance ,                                  ( * env ) -> NewStringUTF ( env , "DES" ) ) ;

 

实例一:

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 /* c/c++ string turn to java jstring */ jstring charToJstring ( JNIEnv* env , const char * pat ) {      jclass strClass = ( * env ) -> FindClass ( env , "java/lang/String" ) ;      jmethodID   ctorID =          ( * env ) -> GetMethodID ( env , strClass , "" ,                                "([BLjava/lang/String;)V" ) ;      jbyteArray bytes = ( * env ) -> NewByteArray ( env , strlen ( pat ) ) ;      ( * env ) -> SetByteArrayRegion ( env , bytes , 0 , strlen ( pat ) , ( jbyte* ) pat ) ;      jstring encoding = ( * env ) -> NewStringUTF ( env , "UTF-8" ) ;      return ( jstring )                ( * env ) -> NewObject ( env , strClass , ctorID , bytes , encoding ) ; }   /* java jstring turn to c/c++ char* */ char * jstringToChar ( JNIEnv* env , jstring jstr ) {      char * pStr = NULL ;      jclass jstrObj = ( * env ) -> FindClass ( env , "java/lang/String" ) ;      jstring encode = ( * env ) -> NewStringUTF ( env , "utf-8" ) ;      jmethodID methodId    =          ( * env ) -> GetMethodID ( env , jstrObj , "getBytes" ,                                        "(Ljava/lang/String;)[B" ) ;      jbyteArray byteArray = ( jbyteArray )          ( * env ) -> CallObjectMethod ( env , jstr , methodId , encode ) ;      jsize strLen = ( * env ) -> GetArrayLength ( env , byteArray ) ;      jbyte * jBuf = ( * env ) -> GetByteArrayElements ( env , byteArray , JNI_FALSE ) ;      if ( jBuf > 0 )      {          pStr = ( char * ) malloc ( strLen + 1 ) ;          if ( ! pStr )          {              return NULL ;          }          memcpy ( pStr , jBuf , strLen ) ;          pStr [ strLen ] = 0 ;      }      env -> ReleaseByteArrayElements ( byteArray , jBuf , 0 ) ;      return pStr ; }

实例二

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include #include #include   jbyteArray decryto                  ( JNIEnv * env ,                    jobject jclazz ,                    jbyteArray paramArrayOfByte ,                    jstring paramString ) {      jclass jc_SecureRandom =          ( * env ) -> FindClass ( env , "java/security/SecureRandom" ) ;      jmethodID jm_constructor =          ( * env ) -> GetMethodID ( env , jc_SecureRandom , "" , "()V" ) ;      jobject jo_SecureRandom =          ( * env ) -> NewObject ( env , jc_SecureRandom , jm_constructor ) ;        jclass   jc_DESKeySpec =          ( * env ) -> FindClass ( env , "javax/crypto/spec/DESKeySpec" ) ;      jmethodID jm_DESKeySpec =          ( * env ) -> GetMethodID ( env , jc_DESKeySpec , "" , "([B)V" ) ;      //DESKeySpec函数的参数是byte[] 返回值是void        jclass jc_string = ( * env ) -> FindClass ( env , "java/lang/String" ) ;      jmethodID jm_getBytes =          ( * env ) -> GetMethodID ( env , jc_string , "getBytes" , "()[B" ) ;      //参数为空,返回值为byte[]      jbyteArray jb_paramString =          ( jbyteArray ) ( * env ) -> CallObjectMethod ( env , paramString , jm_getBytes ) ;        jobject jo_DESKeySpec =          ( * env ) -> NewObject ( env , jc_DESKeySpec , jm_DESKeySpec , jb_paramString ) ;      //new DESKeySpec(ArrayOfByte);        jclass jc_SecretKeyFactory =          ( * env ) -> FindClass ( env , "javax/crypto/SecretKeyFactory" ) ;      jmethodID jm_getInstance =          ( * env ) -> GetMethodID ( env , jc_SecretKeyFactory , "getInstance" ,                      "(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;" ) ;      //getInstance的参数是string,返回值是一个SecretKeyFactory      jobject jo_SecretKeyFactory =          ( * env ) -> CallStaticObjectMethod ( env , jc_SecretKeyFactory ,                              jm_getInstance , ( * env ) -> NewStringUTF ( env , "DES" ) ) ;        jmethodID jm_generateSecret =          ( * env ) -> GetMethodID ( env , jc_SecretKeyFactory , "generateSecret" ,                  "(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;" ) ;      //generateSecret的参数是一个keyspec,返回值是一个secretKey      jobject jo_SecretKey =          ( * env ) -> CallObjectMethod ( env , jc_SecretKeyFactory ,                                        jm_generateSecret , jo_DESKeySpec ) ;        jclass jc_Cipher = ( * env ) -> FindClass ( env , "javax/crypto/Cipher" ) ;      jmethodID jm_Cipher_getInstance =          ( * env ) -> GetStaticMethodID ( env , jc_Cipher , "getInstance" ,                              "(Ljava/lang/String;)Ljavax/crypto/Cipher;" ) ;      //参数是一个string, 返回值是一个Cipher      jobject jo_Cipher =          ( * env ) -> CallStaticObjectMethod ( env , jc_Cipher ,                  jm_Cipher_getInstance , ( * env ) -> NewStringUTF ( env , "DES" ) ) ;        jmethodID jm_Cipher_init =          ( * env ) -> GetMethodID ( env , jc_Cipher , "init" ,                      "(ILjava/security/Key;Ljava/security/SecureRandom;)V" ) ;      ( * env ) -> CallVoidMethod ( env , jc_Cipher , jm_Cipher_init , 2 ,                                            jo_SecretKey , jo_SecureRandom ) ;        jmethodID jm_Cipher_doFinal =          ( * env ) -> GetMethodID ( env , jc_Cipher , "doFinal" , "([B)[B" ) ;      //参数是byte[]  返回值也是byte[]      jbyteArray jb_Resultarr =          ( * env ) -> CallObjectMethod ( env , jc_Cipher , jm_Cipher_doFinal ,                                                      paramArrayOfByte ) ;      //最终结果就保存在jb_Resultarr        return jb_Resultarr ; }   JNIEXPORT jbyteArray JNICALL      Java_com_qihoo_test_first_MainActivity_decry                                                  ( JNIEnv * env ,                                                  jobject thiz ,                                                  jbyteArray paramArrayOfByte ,                                                  jstring paramString )    {        return decryto ( env , thiz , paramArrayOfByte , paramString ) ;    }

 

 

本文出自 0n1y3nd's Blog,转载时请注明出处及相应链接。

本文永久链接: http://0nly3nd.sinaapp.com/?p=277

更多相关文章

  1. Android面试题总结(五)Android基础篇
  2. android之网络编程
  3. Android/java 利用HttpUrlConnection 发送put请求,携带json参数
  4. Android(安卓)开发学习小结(五)
  5. android:persistent属性
  6. 【Android】使用Gallery组件实现循环显示图像
  7. 阅读Android消息机制源码的随手笔记
  8. 为何GoogleSearch中可以嵌入EditText?
  9. Android(安卓)应用权限管理默认开关的修改方法

随机推荐

  1. 子线程新建Handler为什么会报错?——浅谈H
  2. Android:开发自己的Launcher简单demo
  3. Android Jni 开发(Android studio)
  4. 一份关于 Java、Kotlin 与 Android 的学
  5. Android packageManagerService如何添加
  6. android面试经验浅谈
  7. Android(安卓)Q 深色模式(Dark Mode)源码解
  8. Android消息处理系统——Looper、Handler
  9. 注意android裁图的Intent action
  10. App"确定"按钮应该在左边还是右边?