Android中JNI調用

http://blog.csdn.net/xyz_lmn/article/details/6955031

  android支持使用NDK開發C程序,關於配置NDK環境問題應該不用再贅述了,這個網上有很多,這裏通過一篇實例來講述簡單的JNI開發,大家可以參考這篇文章(Get Your Eclipse-Integrated NDK On!)搭建Eclipse編譯C語言爲so文件的開發環境。

        native方法實現步驟如下:

        1、在Java中聲明native()方法,然後編譯(javac); 

      2、用javah產生一個.h文件; 

      3、編寫包含.h文件的c文件

      4、編譯c文件

      5、使用編譯成功的so文件。

 

       第一步:

              1、聲明native方法

                 

[java] view plaincopy
  1. public class Printf_Jni {  
  2.   
  3.      static {  
  4.             System.loadLibrary("com_nedu_jni_helloword_printf-jni");  
  5.         }  
  6.     public native void printHello();  
  7. }  

       2、javac編譯

            進入java文件所在路徑,調用javac命令,如圖:

             

第二步:使用javah命令生成.h頭文件,如圖:

           

     這個要回到src目錄下,不知道什麼原因,如果在上面的javac路徑下會報錯,如圖:

       

      使用javah命令生成的頭文件如下:

  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_nedu_jni_helloword_Printf_Jni */  
  4.   
  5. #ifndef _Included_com_nedu_jni_helloword_Printf_Jni  
  6. #define _Included_com_nedu_jni_helloword_Printf_Jni  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_nedu_jni_helloword_Printf_Jni 
  12.  * Method:    printHello 
  13.  * Signature: ()V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_com_nedu_jni_helloword_Printf_1Jni_printHello  
  16.   (JNIEnv *, jobject);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  

第三步:編寫c文件,代碼如下:

  1. #include<stdio.h>    
  2. #include <stdlib.h>    
  3. #include "com_nedu_jni_helloword_Printf_Jni.h"    
  4. JNIEXPORT void JNICALL Java_com_nedu_jni_helloword_Printf_1Jni_printHello  
  5.   (JNIEnv *e, jobject j)    
  6. {    
  7.     printf("Hello world!");   
  8. }    

第四步,書寫Android.mk文件,編譯c文件
        Android.mk文件如下:

     

[plain] view plaincopy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := com_nedu_jni_helloword_printf-jni  
  6. LOCAL_SRC_FILES :=Printf_Jni.c  
  7.   
  8. include $(BUILD_SHARED_LIBRARY)  


LOCAL_MODULE    := com_nedu_jni_helloword_printf-jniLOCAL_MODULE    := com_nedu_jni_helloword_printf-jniLOCAL_MODULE  表示so文件名

LOCAL_SRC_FILES 需要編譯的文件

按照這篇文章(Get Your Eclipse-Integrated NDK On!)的介紹就可以在Eclipse編譯了。

第五步:使用so文件:

    通過下面的代碼加載so文件

[html] view plaincopy
  1. System.loadLibrary("com_nedu_jni_helloword_printf-jni");  


通過下面的代碼加載so文件通過下面的代碼加載so文件

調用如下:

[java] view plaincopy
  1. Printf_Jni print=new Printf_Jni();   
[java] view plaincopy
  1. print.printHello();  

 

http://blog.csdn.net/xyz_lmn/article/details/6956003

 前面一篇通過簡單的例子介紹了android中JNI的使用。這一篇從基礎上了解一些Java參數類型與本地參數類型區別。

 

1)        java中的返回值voidJNI中的void是完全對應的哦!(僅僅一個而已)。

2)        java中的基本數據類型(byte ,short ,int,long,float,double ,boolean,char8種)在JNI中對應的數據類型只要在前面加上j就對應了(jbyte ,jshort ,jint,jlong,jfloat,jdouble ,jboolean,jchar)。

3)        java中的對象,包括類庫中定義的類、接口以及自定義的類接口,都對應於JNI中的jobject

4)        java中基本數據類型的數組對應與JNI中的j<type>array類型。(type就是上面說的8種基本數據類型)

5)        java中對象的數組對應於JNI中的jobjectArray類型。(在java中一切對象、接口以及數組都是對象)

 

       下圖是JNI規範中java數據類型和JNI數據類型的映射圖。

       第一幅爲基本數據類型的映射圖:

 

 

  第二幅爲引用數據類型的映射圖:

http://blog.csdn.net/xyz_lmn/article/details/6959545

一、 首先寫了java文件:

[java] view plaincopy
  1. public class HeaderFile {  
  2.     private native void  doVoid();  
  3.     native int doShort();  
  4.     native void doArray(Object[] o );  
  5.     native int doInt(int i);      //byte ,short ,int,long,float,double ,boolean,char        
  6.     native int doInt(double d);    //byte ,short ,int,long,float,double ,boolean,char  
  7.     native int doInt(Object o);      
  8.     native int doInt(double d1,double d2);  
  9.     static native int doInt(double d1 ,double d2,double d3);  
  10.     static native int doInt(double d1 ,float f,boolean b ,char[] c );    
  11.      
  12.     native int doInt(int[] i);  
  13.     native int doInt(int[] i1,double[] i2 );      
  14.     static native int doInt(int[] i1,double[] i2 ,Object[] o );  
  15.      
  16.     public native String doString(String s);  
  17.     public native Object doObject(Object o );  
  18.     public native Enumeration doInterface(Iterator it);  
  19.     public native Student doStudent(Student s);  
  20.      
  21. //  native int[] doInt(int[] i);  //byte ,short ,int,long,float,double ,boolean,char  
  22.     public native String[] doString(String[] s);  
  23.     public native Object[] doObjects(Object[] o );  
  24.     public native Enumeration[] doInterface(Iterator[] it);  
  25.     public native Student[] doStudent(Student[] s);  
  26.             
  27.     public native static Object doAll(int[] i , String[] s , Student[] student );               
  28. }  

                         java文件中包含了private、public、protect等類型的方法,static 方法和非static 方法,返回類型有基礎類型、對象等。

           二、下面看一下生成的頭文件:

  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_nedu_jni_helloword_HeaderFile */  
  4.   
  5. #ifndef _Included_com_nedu_jni_helloword_HeaderFile  
  6. #define _Included_com_nedu_jni_helloword_HeaderFile  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_nedu_jni_helloword_HeaderFile 
  12.  * Method:    doVoid 
  13.  * Signature: ()V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_com_nedu_jni_helloword_HeaderFile_doVoid  
  16.   (JNIEnv *, jobject);  
  17.   
  18. /* 
  19.  * Class:     com_nedu_jni_helloword_HeaderFile 
  20.  * Method:    doShort 
  21.  * Signature: ()I 
  22.  */  
  23. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doShort  
  24.   (JNIEnv *, jobject);  
  25.   
  26. /* 
  27.  * Class:     com_nedu_jni_helloword_HeaderFile 
  28.  * Method:    doArray 
  29.  * Signature: ([Ljava/lang/Object;)V 
  30.  */  
  31. JNIEXPORT void JNICALL Java_com_nedu_jni_helloword_HeaderFile_doArray  
  32.   (JNIEnv *, jobject, jobjectArray);  
  33.   
  34. /* 
  35.  * Class:     com_nedu_jni_helloword_HeaderFile 
  36.  * Method:    doInt 
  37.  * Signature: (I)I 
  38.  */  
  39. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__I  
  40.   (JNIEnv *, jobject, jint);  
  41.   
  42. /* 
  43.  * Class:     com_nedu_jni_helloword_HeaderFile 
  44.  * Method:    doInt 
  45.  * Signature: (D)I 
  46.  */  
  47. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__D  
  48.   (JNIEnv *, jobject, jdouble);  
  49.   
  50. /* 
  51.  * Class:     com_nedu_jni_helloword_HeaderFile 
  52.  * Method:    doInt 
  53.  * Signature: (Ljava/lang/Object;)I 
  54.  */  
  55. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__Ljava_lang_Object_2  
  56.   (JNIEnv *, jobject, jobject);  
  57.   
  58. /* 
  59.  * Class:     com_nedu_jni_helloword_HeaderFile 
  60.  * Method:    doInt 
  61.  * Signature: (DD)I 
  62.  */  
  63. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__DD  
  64.   (JNIEnv *, jobject, jdouble, jdouble);  
  65.   
  66. /* 
  67.  * Class:     com_nedu_jni_helloword_HeaderFile 
  68.  * Method:    doInt 
  69.  * Signature: (DDD)I 
  70.  */  
  71. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__DDD  
  72.   (JNIEnv *, jclass, jdouble, jdouble, jdouble);  
  73.   
  74. /* 
  75.  * Class:     com_nedu_jni_helloword_HeaderFile 
  76.  * Method:    doInt 
  77.  * Signature: (DFZ[C)I 
  78.  */  
  79. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__DFZ_3C  
  80.   (JNIEnv *, jclass, jdouble, jfloat, jboolean, jcharArray);  
  81.   
  82. /* 
  83.  * Class:     com_nedu_jni_helloword_HeaderFile 
  84.  * Method:    doInt 
  85.  * Signature: ([I)I 
  86.  */  
  87. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt___3I  
  88.   (JNIEnv *, jobject, jintArray);  
  89.   
  90. /* 
  91.  * Class:     com_nedu_jni_helloword_HeaderFile 
  92.  * Method:    doInt 
  93.  * Signature: ([I[D)I 
  94.  */  
  95. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt___3I_3D  
  96.   (JNIEnv *, jobject, jintArray, jdoubleArray);  
  97.   
  98. /* 
  99.  * Class:     com_nedu_jni_helloword_HeaderFile 
  100.  * Method:    doInt 
  101.  * Signature: ([I[D[Ljava/lang/Object;)I 
  102.  */  
  103. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt___3I_3D_3Ljava_lang_Object_2  
  104.   (JNIEnv *, jclass, jintArray, jdoubleArray, jobjectArray);  
  105.   
  106. /* 
  107.  * Class:     com_nedu_jni_helloword_HeaderFile 
  108.  * Method:    doString 
  109.  * Signature: (Ljava/lang/String;)Ljava/lang/String; 
  110.  */  
  111. JNIEXPORT jstring JNICALL Java_com_nedu_jni_helloword_HeaderFile_doString__Ljava_lang_String_2  
  112.   (JNIEnv *, jobject, jstring);  
  113.   
  114. /* 
  115.  * Class:     com_nedu_jni_helloword_HeaderFile 
  116.  * Method:    doObject 
  117.  * Signature: (Ljava/lang/Object;)Ljava/lang/Object; 
  118.  */  
  119. JNIEXPORT jobject JNICALL Java_com_nedu_jni_helloword_HeaderFile_doObject  
  120.   (JNIEnv *, jobject, jobject);  
  121.   
  122. /* 
  123.  * Class:     com_nedu_jni_helloword_HeaderFile 
  124.  * Method:    doInterface 
  125.  * Signature: (Ljava/util/Iterator;)Ljava/util/Enumeration; 
  126.  */  
  127. JNIEXPORT jobject JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInterface__Ljava_util_Iterator_2  
  128.   (JNIEnv *, jobject, jobject);  
  129.   
  130. /* 
  131.  * Class:     com_nedu_jni_helloword_HeaderFile 
  132.  * Method:    doStudent 
  133.  * Signature: (Lcom/nedu/jni/helloword/Student;)Lcom/nedu/jni/helloword/Student; 
  134.  */  
  135. JNIEXPORT jobject JNICALL Java_com_nedu_jni_helloword_HeaderFile_doStudent__Lcom_nedu_jni_helloword_Student_2  
  136.   (JNIEnv *, jobject, jobject);  
  137.   
  138. /* 
  139.  * Class:     com_nedu_jni_helloword_HeaderFile 
  140.  * Method:    doString 
  141.  * Signature: ([Ljava/lang/String;)[Ljava/lang/String; 
  142.  */  
  143. JNIEXPORT jobjectArray JNICALL Java_com_nedu_jni_helloword_HeaderFile_doString___3Ljava_lang_String_2  
  144.   (JNIEnv *, jobject, jobjectArray);  
  145.   
  146. /* 
  147.  * Class:     com_nedu_jni_helloword_HeaderFile 
  148.  * Method:    doObjects 
  149.  * Signature: ([Ljava/lang/Object;)[Ljava/lang/Object; 
  150.  */  
  151. JNIEXPORT jobjectArray JNICALL Java_com_nedu_jni_helloword_HeaderFile_doObjects  
  152.   (JNIEnv *, jobject, jobjectArray);  
  153.   
  154. /* 
  155.  * Class:     com_nedu_jni_helloword_HeaderFile 
  156.  * Method:    doInterface 
  157.  * Signature: ([Ljava/util/Iterator;)[Ljava/util/Enumeration; 
  158.  */  
  159. JNIEXPORT jobjectArray JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInterface___3Ljava_util_Iterator_2  
  160.   (JNIEnv *, jobject, jobjectArray);  
  161.   
  162. /* 
  163.  * Class:     com_nedu_jni_helloword_HeaderFile 
  164.  * Method:    doStudent 
  165.  * Signature: ([Lcom/nedu/jni/helloword/Student;)[Lcom/nedu/jni/helloword/Student; 
  166.  */  
  167. JNIEXPORT jobjectArray JNICALL Java_com_nedu_jni_helloword_HeaderFile_doStudent___3Lcom_nedu_jni_helloword_Student_2  
  168.   (JNIEnv *, jobject, jobjectArray);  
  169.   
  170. /* 
  171.  * Class:     com_nedu_jni_helloword_HeaderFile 
  172.  * Method:    doAll 
  173.  * Signature: ([I[Ljava/lang/String;[Lcom/nedu/jni/helloword/Student;)Ljava/lang/Object; 
  174.  */  
  175. JNIEXPORT jobject JNICALL Java_com_nedu_jni_helloword_HeaderFile_doAll  
  176.   (JNIEnv *, jclass, jintArray, jobjectArray, jobjectArray);  
  177.   
  178. #ifdef __cplusplus  
  179. }  
  180. #endif  
  181. #endif  


         三、頭文件分析如下:

                       1、文件的前九行就不用說了,他們是CC++的頭,應該很好理解。

          2、方法的註釋部分,每個方法都有它的註釋部分,這些都是相似的,對其中一個分析:

[plain] view plaincopy
  1. /*  
  2.  * Class:     com_nedu_jni_helloword_HeaderFile  
  3.  * Method:    doVoid  
  4.  * Signature: ()V  
  5.  */  

註釋部分分爲三部分Class、Method、Signature。

Class:表示Native方法的類名稱

Method:表示方法名稱

Signature:是方法的標識,它是一個標識符,主要供我們在JNI操作java對象的方法使用的。

Signature一般是兩部分構成,一個方法的參數,另一個是返回類型。方法參數在括號裏面,返回類型在後面,

例如

[plain] view plaincopy
  1. ()V 返回爲void,沒有參數。  
[plain] view plaincopy
  1. (DFZ[C)I 返回爲int,參數爲double、float、char[]  
[plain] view plaincopy
  1. (Ljava/lang/String;)Ljava/lang/String;返回String,參數爲String  


如果不清楚其中的字符含義,就不能知道其中的意思,其中字符對應有基本類型、對象類型、數組類型。分析如下

1)基本類型的對應關係如下:

2) 方法參數或者返回值爲java中的對象時,必須以“L”加上其路徑,不過此路徑必須以“/”分開,自定義的對象也使用本規則,不在包中時直接“L”加上類名稱。比如說java.lang.String爲“java/lang/String”,com.nedu.jni.helloword.Student爲"com/nedu/jni/helloword/Student"

3)方法參數或者返回值爲數組時類型前加上[,例如[I表示int[],[[[D表示 double[][][],即幾維數組就加幾個[。

看一下例子:

3、方法的聲明

  1. JNIEXPORT void JNICALL Java_com_nedu_jni_helloword_HeaderFile_doArray(JNIEnv *,jobject,jobjectArray);  

      從上面的頭文件可以看出方法基本有7部分組成。

          

1、3部分是都是JNI的關鍵字,表示此函數是要被JNI調用的。

2、表示方法的返回類型

4、JNI中標識此方法來源於java的標識頭

5、方法所在類的包名+類名

6、方法名

7、參數,它們有一個共同的特點,包含JNIEnv *――它是一個接口指針,用於定位函數表中的函數!

     在JNI規範中一般稱  爲   “Interface Pointer”。看到這兒好像和過程調用很類似了!是的,JNI

     的操作過程,就是面向過程的!後面的jobject是  一個指向該類的指針,類似與C語言中的this。這個

     第二個參數是變化的,當該方法爲類的實例方法時該參數爲jobject;當該方法爲類方法(即靜態方法)

     時該參數爲jclass,指向該類的class

根據不同方法前綴生成的頭文件比較如下:

1、static與非static的比較:

  1. /* 
  2.  * Class:     com_nedu_jni_helloword_HeaderFile 
  3.  * Method:    doInt 
  4.  * Signature: (DD)I 
  5.  */  
  6. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__DD  
  7.   (JNIEnv *, <span style="background-color: rgb(255, 0, 0);">jobject</span>, jdouble, jdouble);  
  8.   
  9. /* 
  10.  * Class:     com_nedu_jni_helloword_HeaderFile 
  11.  * Method:    doInt 
  12.  * Signature: (DDD)I 
  13.  */  
  14. JNIEXPORT jint JNICALL Java_com_nedu_jni_helloword_HeaderFile_doInt__DDD  
  15.   (JNIEnv *, <span style="color:#000000;background-color: rgb(255, 0, 0);">jclass</span>, jdouble, jdouble, jdouble);  

第一個是非static方法,第二個是static方法,不同點如上紅色標記。其中的不同將在以後提到。

2、 privatefriendlyprotected以及public這些方法限制符不會在JNI的頭文件中出現。這些訪問修飾符只有在其它類

       使用這些方法時有效!JNI中不關心此修飾符!

http://blog.csdn.net/xyz_lmn/article/details/6966259

Android.mk文件是在使用NDK編譯C代碼時必須的文件,Android.mk文件中描述了哪些C文件將被編譯且指明瞭如何編譯。掌握Android.mk文件的編寫主要是掌握其裏頭將要使用的一些關鍵字,先來看一個簡單的例子,這個例子使用的是android NDK帶的

HellJni的例子。

[plain] view plaincopy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := hello-jni  
  6. LOCAL_SRC_FILES := hello-jni.c  
  7.   
  8. include $(BUILD_SHARED_LIBRARY)  


 

LOCAL_PATH 是描述所有要編譯的C文件所在的根目錄,這邊的賦值爲$(call my-dir),代表根目錄即爲Android.mk所在的目錄。

 

include $(CLEAR_VARS) 代表在使用NDK編譯工具時對編譯環境中所用到的全局變量清零,如LOCAL_MODULE,LOCAL_SRC_FILES等,因爲在一次NDK編譯過程中可能會多次調用Android.mk文件,中間用到的全局變量可能是變化的。關於這個問題看了下面比較複雜的例子可能就明白了。

 

LOCAL_MODULE 是最後生成庫時的名字的一部分,給其加上前綴lib和後綴.so就是生成的共享庫的名字libhello-jni.so。

 

LOCAL_SRC_FILES 指明要被編譯的c文件的文件名

 

include $(BUILD_SHARED_LIBRARY) 指明NDK編譯時將生成一些共享庫

 

 

參考:

 

android編譯系統makefile(Android.mk)寫法

 

android makefile(android.mk)分析(序)

 

Android.mk的用法和基礎

 


<!-- JiaThis Button BEGIN -->
<div id="ckepop">
 <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt" target="_blank"><img src="http://v2.jiathis.com/code_mini/images/btn/v1/jiathis1.gif" border="0" /></a>
 <a class="jiathis_counter_style_margin:3px 0 0 2px"></a>
</div>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jia.js" charset="utf-8"></script>
<!-- JiaThis Button END --><!-- JiaThis Button BEGIN -->
<div id="ckepop">
 <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt" target="_blank"><img src="http://v2.jiathis.com/code_mini/images/btn/v1/jiathis1.gif" border="0" /></a>
 <a class="jiathis_counter_style_margin:3px 0 0 2px"></a>
</div>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jia.js" charset="utf-8"></script>
<!-- JiaThis Button END -->

 

參考網址:

http://blog.csdn.net/xyz_lmn/article/details/6959545

 Android JNI入門第三篇——jni頭文件分析 

http://blog.csdn.net/xyz_lmn/article/details/6966259

 Android JNI入門第四篇——Android.mk文件分析

http://blog.csdn.net/xyz_lmn/article/details/7017420

 Android JNI開發提高篇 

http://blog.csdn.net/xyz_lmn/article/details/6956003

 Android JNI入門第二篇——Java參數類型與本地參數類型對照

 

http://wenku.baidu.com/view/e9e28ca1b0717fd5360cdc18.html

JNI入門

http://www.ibm.com/developerworks/cn/java/j-jni/

使用 Java Native Interface 的最佳實踐

http://helloxuweifu.iteye.com/blog/1168647

http://blog.csdn.net/kangyaping/article/details/6584027

JNI函數調用大全

 

http://newfaction.net/2010/11/30/java-jni-getfieldid-and-getmethodid-and-parameter-description.html

java jni GetFieldID 和 GetMethodID 以及參數的說明

http://hi.baidu.com/spmno/blog/item/7d4d764ea78a6809b3de0588.html

jni中使用數組的幾個方法

http://xxw8393.blog.163.com/blog/static/3725683420107109411366/

JNI 返回結構體參數 

http://www.cnblogs.com/nicholas_f/archive/2010/11/30/1892124.html

JNI中java類型與C/C++類型對應關係

http://blog.csdn.net/sunny09290/article/details/6884994

JNI數據類型

http://www.cnblogs.com/liangwind/archive/2009/08/18/1925515.html

jni --c/c++ 數據類型、數組、對象

http://www.cnblogs.com/diyunpeng/archive/2009/09/24/1573296.html

Java有符號數與無符號數

http://www.stuhack.com/biancheng/java/35169.html

Java的基本數據類型是無符號的


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章