一、使用環境 1、windows32位操作系統 2、ADT爲adt-bundle-windows-x86-20131030 3、NDK爲android-ndk-r9d
二、配置生成頭文件.h
⒈首先,如圖所示,點擊External Tools Configurations...
⒉然後,如圖所示,點擊
⒊接下來,看圖操作
最後點擊Apply,然後 我們在一個android工程中新建一個class文件
三、配置build ndk,和上面類似,參考圖中配置即可
創建C文件
創建Android.mk文件
創建Application.mk文件
最後 加載so的庫文件 就可以把C語言的函數當Java函數使用了
編譯結果:
Jni中數據類型對應關係
瞭解了jni的簡單用法,我們再來進行深入的學習:首先使jni中Java基本類型和C基本類型的對應關係
訪問Java中的域
使用C語言訪問Java中的域和方法都要知道其Id,使用起來相對也比較複雜,在這裏舉一個簡單的例子,假設我們的類People中有一個int類型的域age,即:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">package com.example.jnitest; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> People { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">getAge</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> age; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setAge</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> age) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.age = age; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
修改JniTest中的方法,這一次我們通過調用native方法使得age域變爲原來的二倍:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.example.jnitest; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">JniTest</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">native</span> People <span class="hljs-title" style="box-sizing: border-box;">changeAge</span>(People people); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
重新生成頭文件後再cpp文件中編寫我們的方法,每次訪問Java中的域我們需要得到FieldId纔可以,其步驟爲:
1. 獲取隱式參數的類
2. 獲取域Id
3. 訪問域的值
<code class="hljs scala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">#include<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jni_hello.h"</span> JNIEXPORT j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">object</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">JNICALL</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Java_com_example_jnitest_JniTest_changeAge</span></span> (JNIEnv *env, j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">cl</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">jobject</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ob</span>){</span> j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">cl_people</span> = <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">env</span>-><span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">GetObjectClass</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(ob)</span>;</span> jfieldID c_ageId = env->GetFieldID(cl_people, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"I"</span>); jint c_age = env->GetIntField(ob,c_ageId); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//打印修改之後的語句</span> printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d"</span>, c_age); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//修改age域</span> env->SetIntField(ob, c_ageId, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>*c_age); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ob; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
env->GetFieldID方法中的第二個參數表示該域的名稱,第三個參數表示該age域的類型爲int,這個jni的編碼簽名有關,稍後會提到。接下來在main方法中調用:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">package com.example.jnitest; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Main { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span>{ System.loadLibrary(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"JniApplication"</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) { People people = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> People(); people.setAge(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>); people = JniTest.changeAge(people); System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"changed::"</span>+people.getAge()); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
輸出結果:
可以看到,結果變爲原來的2倍。對於訪問靜態域時只需更換env->GetIntField爲env->GetStaticIntField即可。
訪問Java中的方法
剛剛我們使用了訪問域的方法去修改了域的值,下面我們在cpp文件中調用People類下的setAge方法修改age的值;調用Java的方法需要按照以下步驟:
- 獲取隱式參數的類
- 獲取方法Id
- 進行調用
<code class="hljs scala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">#include<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jni_hello.h"</span> JNIEXPORT j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">object</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">JNICALL</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Java_com_example_jnitest_JniTest_changeAge</span></span> (JNIEnv *env, j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">cl</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">jobject</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ob</span>){</span> j<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">cl_people</span> = <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">env</span>-><span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">GetObjectClass</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(ob)</span>;</span> jfieldID c_ageId = env->GetFieldID(cl_people, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"age"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"I"</span>); jint c_age = env->GetIntField(ob,c_ageId); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//第三個參數同樣和編碼簽名有關</span> jmethodID c_setAgeId = env->GetMethodID(cl_people, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"setAge"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"(I)V"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//void表示了返回類型,若返回爲int,則調用CallIntMethod</span> env->CallVoidMethod(ob,c_setAgeId,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>*c_age); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ob; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
在main函數中調用,代碼同上,結果如下:
對於static方法的調用,我們只需要將調用時的方法更換就好,例如setAge方法爲static的話,只需將 env->CallVoidMethod(ob,c_setAgeId,2*c_age);更換爲 env->CallStaticVoidMethod(ob,c_setAgeId,2*c_age);即可。
Jni編碼簽名
在前面我們提到了env->GetFieldID方法中的第三個參數用編碼簽名來表示了該域的數據類型,現在來介紹一下jni中數據類的對應關係。
- 基本數據類型:
B——byte, C——char, D——double, F——float,
I——-int , J——long, S——short, V——–void , Z——boolean - 數組類型,在開頭加“[”來表示,如int[] 數組爲“[I”;二維數組int[][] 即爲“[[I”
- 類類型,以“L+完整包名+類名+;”表示其中所有的“.”換爲“/”,如com.example.jnitest.People類表示爲Lcom/example/jnitest/People;
關於方法的編碼簽名規則是,“(傳入參數類型的編碼簽名)+返回參數類型的編碼簽名”,多個傳入參數之間直接相接就好;例如我們的setAge方法中傳入參數爲int,返回爲void,則表示爲“(I)V”。
好了,上面就是是用eclipse快速開發JNI的方法了,你學會了嗎?
參考文章:
http://blog.csdn.net/smbroe/article/details/44133741