Java指導(dǎo)JNI完全手冊_第1頁
Java指導(dǎo)JNI完全手冊_第2頁
Java指導(dǎo)JNI完全手冊_第3頁
Java指導(dǎo)JNI完全手冊_第4頁
Java指導(dǎo)JNI完全手冊_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、Java 指導(dǎo):JNI 完全手冊最近在公司里做了一個手機(jī)的項(xiàng)目,需要 JAVA 程序在發(fā)送短信的時候和第三方的短信服務(wù)器連接。短信接口是用 C+寫的。琢磨了三天,大致搞懂了 JNI 的主體部分。先將心得整理,希望各位朋友少走彎路。首先引用一篇文章,介紹一個簡單的 JNI 的調(diào)用的過程。JAVA 以其跨平臺的特性深受人們喜愛,而又正由于它的跨平臺的目的,使得它和本地機(jī)器的各種內(nèi)部聯(lián)系變得很少,約束了它的功能。解決 JAVA 對本地操作的一種方法就是 JNI。JAVA 通過 JNI 調(diào)用本地方法,而本地方法是以庫文件的形式存放的(在WINDOWS 平臺上是 DLL 文件形式,在 UNIX 機(jī)器上是

2、 SO 文件形式)。通過調(diào)用本地的庫文件的內(nèi)部方法,使 JAVA 可以實(shí)現(xiàn)和本地機(jī)器的緊密聯(lián)系,調(diào)用系統(tǒng)級的各接口方法。簡單介紹及應(yīng)用如下:一、JAVA 中所需要做的工作在 JAVA 程序中,首先需要在類中聲明所調(diào)用的庫名稱,如下:static System.loadLibrary(“goodluck”);在這里,庫的擴(kuò)展名字可以不用寫出來,究竟是 DLL 還是 SO,由系統(tǒng)自己判斷。還需對將要調(diào)用的方法做本地聲明,關(guān)鍵字為 native。且只需要聲明,而不需要具體實(shí)現(xiàn)。如下:public native static void set(int i);public native static i

3、nt get();然后編譯該 JAVA 程序文件,生成 CLASS,再用 JAVAH 命令,JNI 就會生成C/C+的頭文件。例如程序 testdll.java,內(nèi)容為:public class testdllstaticSystem.loadLibrary(goodluck);public native static int get();public native static void set(int i);public static void main(String args)testdll test = new testdll();test.set(10);System.out.pri

4、ntln(test.get();用 javac testdll.java 編譯它,會生成 testdll.class。再用 javah testdll,則會在當(dāng)前目錄下生成 testdll.h 文件,這個文件需要被 C/C+程序調(diào)用來生成所需的庫文件。二、C/C+中所需要做的工作對于已生成的.h 頭文件,C/C+所需要做的,就是把它的各個方法具體的實(shí)現(xiàn)。然后編譯連接成庫文件即可。再把庫文件拷貝到 JAVA 程序的路徑下面,就可以用 JAVA 調(diào)用 C/C+所實(shí)現(xiàn)的功能了。接上例子。我們先看一下 testdll.h 文件的內(nèi)容:/* DO NOT EDIT THIS FILE - it is m

5、achine generated */#include/* Header for class testdll */#ifndef _Included_testdll#define _Included_testdll#ifdef _cplusplusextern C #endif/* Class: testdll* Method: get* Signature: ()I*/JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);/* Class: testdll* Method: set* Signature: (I)V*/JNIEX

6、PORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);#ifdef _cplusplus#endif#endif在具體實(shí)現(xiàn)的時候,我們只關(guān)心兩個函數(shù)原型JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);這里 JNIEXPORT 和 JNICALL 都是 JNI 的關(guān)鍵字,表示此函數(shù)是要被 JNI 調(diào)用的。而 jint 是以 JNI

7、 為中介使 JAVA 的 int 類型與本地的 int 溝通的一種類型,我們可以視而不見,就當(dāng)做 int 使用。函數(shù)的名稱是 JAVA_再加上 java 程序的 package 路徑再加函數(shù)名組成的。參數(shù)中,我們也只需要關(guān)心在 JAVA 程序中存在的參數(shù),至于 JNIEnv*和 jclass 我們一般沒有必要去碰它。好,下面我們用 testdll.cpp 文件具體實(shí)現(xiàn)這兩個函數(shù):#include testdll.hint i = 0;JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)return i;JNIEXPORT void

8、 JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)i = j;編譯連接成庫文件,本例是在 WINDOWS 下做的,生成的是 DLL 文件。并且名稱要與 JAVA 中需要調(diào)用的一致,這里就是 goodluck.dll 。把 goodluck.dll拷貝到 testdll.class 的目錄下,java testdll 運(yùn)行它,就可以觀察到結(jié)果了。我的項(xiàng)目比較復(fù)雜,需要調(diào)用動態(tài)鏈接庫,這樣在 JNI 傳送參數(shù)到 C 程序時,需要對參數(shù)進(jìn)行處理轉(zhuǎn)換。才可以被 C 程序識別。大體程序如下:public class SendSMS staticSys

9、tem.out.println(System.getProperty(java.library.path);System.loadLibrary(sms);public native static int SmsInit();public native static int SmsSend(byte mobileNo, byte smContent);在這里要注意的是,path 里一定要包含類庫的路徑,否則在程序運(yùn)行時會拋出異常:java.lang.UnsatisfiedLinkError: no sms in java.library.pathat java.lang.ClassLoader

10、.loadLibrary(ClassLoader.java:1491)at java.lang.Runtime.loadLibrary0(Runtime.java:788)at java.lang.System.loadLibrary(System.java:834)at com.mobilesoft.sms.mobilesoftinfo.SendSMS.(SendSMS.java:14)at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)Exception in thread main指引的路徑應(yīng)該到.dll 文件的上一級,

11、如果指到.dll,則會報:java.lang.UnsatisfiedLinkError: C:sms.dll: Cant find dependentlibrariesat java.lang.ClassLoader$NativeLibrary.load(Native Method)at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)at java.lang.Runtime.loadLibrary0(Runti

12、me.java:788)at java.lang.System.loadLibrary(System.java:834)at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)Exception in thread main通過編譯,生成 com_mobilesoft_sms_mobilesoftinfo_SendSMS.h 頭文件。(建議使用 Jbuilder 進(jìn)行編譯,操作比較簡單!)這個頭文件就是 Java和 C 之間的紐帶。要特別注意的是方法中傳遞的參數(shù) jbyteArray,這在接下來的過程中會重點(diǎn)介紹。/* DO NO

13、T EDIT THIS FILE - it is machine generated */#include/* Header for class com_mobilesoft_sms_mobilesoftinfo_SendSMS */#ifndef _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS#define _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS#ifdef _cplusplusextern C #endif/* Class: com_mobilesoft_sms_mobi

14、lesoftinfo_SendSMS* Method: SmsInit* Signature: ()I*/JNIEXPORT jint JNICALLJava_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv *, jclass);/* Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS* Method: SmsSend* Signature: (BB)I*/JNIEXPORT jint JNICALLJava_com_mobilesoft_sms_mobilesoftinfo_Sen

15、dSMS_SmsSend(JNIEnv *, jclass, jbyteArray, jbyteArray);#ifdef _cplusplus#endif#endif對于我要調(diào)用的 C 程序的動態(tài)鏈接庫,C 程序也要提供一個頭文件,sms.h。這個文件將要調(diào)用的方法羅列了出來。/* SMS API* Author: yippit* Date: 2004.6.8*/#ifndef MCS_SMS_H#define MCS_SMS_H#define DLLEXPORT _declspec(dllexport)/*sms storage*/#define SMS_SIM 0#define SMS_

16、MT 1/*sms states*/#define SMS_UNREAD 0#define SMS_READ 1/*sms type*/#define SMS_NOPARSE -1#define SMS_NORMAL 0#define SMS_FLASH 1#define SMS_MMSNOTI 2typedef struct tagSmsEntry int index; /*index, start from 1*/int status; /*read, unread*/int type; /*-1-cant parser 0-normal, 1-flash, 2-mms*/int stor

17、age; /*SMS_SIM, SMS_MT*/char date24;char number32;char text144; SmsEntry;DLLEXPORT int SmsInit(void);DLLEXPORT int SmsSend(char *phonenum, char *content);DLLEXPORT int SmsSetSCA(char *sca);DLLEXPORT int SmsGetSCA(char *sca);DLLEXPORT int SmsSetInd(int ind);DLLEXPORT int SmsGetInd(void);DLLEXPORT int

18、 SmsGetInfo(int storage, int *max, int *used);DLLEXPORT int SmsSaveFlash(int flag);DLLEXPORT int SmsRead(SmsEntry *entry, int storage, int index);DLLEXPORT int SmsDelete(int storage, int index);DLLEXPORT int SmsModifyStatus(int storage, int index); /*unread -read*/#endif在有了這兩個頭文件之后,就可以進(jìn)行 C 程序的編寫了。也就

19、是實(shí)現(xiàn)對JNI 調(diào)用的兩個方法。在網(wǎng)上的資料中,由于調(diào)用的方法實(shí)現(xiàn)的都比較簡單,(大多是打印字符串等)所以避開了 JNI 中最麻煩的部分,也是最關(guān)鍵的部分,參數(shù)的傳遞。由于 Java 和 C 的編碼是不同的,所以傳遞的參數(shù)是要進(jìn)行再處理,否則 C 程序是會對參數(shù)在編譯過程中提出警告,例如;warningC4024: SmsSend : different types for formal and actual parameter2 等。Sms.c 的程序如下:#include sms.h#include com_mobilesoft_sms_mobilesoftinfo_SendSMS.hJN

20、IEXPORT jint JNICALLJava_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv * env,jclass jobject)return SmsInit();JNIEXPORT jint JNICALLJava_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend(JNIEnv * env,jclass jobject, jbyteArray mobileno, jbyteArray smscontent)char * pSmscontent ;/jsize theA

21、rrayLengthJ = (*env)-GetArrayLength(env,mobileno);jbyte * arrayBody = (*env)-GetByteArrayElements(env,mobileno,0);char * pMobileNo = (char *)arrayBody;printf(%s , pMobileNo);/jsize size = (*env)-GetArrayLength(env,smscontent);arrayBody = (*env)-GetByteArrayElements(env,smscontent,0);pSmscontent = (c

22、har *)arrayBody;printf( , pSmscontent);return SmsSend(pMobileNo,pSmscontent);對于 C 或 C+,在程序上是會有稍微的不同,這可以由讀者對其進(jìn)行適當(dāng)?shù)男薷?。這里要注意的是 GetArrayLength,GetByteArrayElements 等這些 JNI中已經(jīng)包含的方法,這些方法是專門對轉(zhuǎn)換參數(shù)類型而提供的。具體的方法有很多,在下一篇中會做專門的介紹。在完成了上述的文件后,可以對 sms.c 進(jìn)行編譯,生成.dll 文件(建議在release 中編譯,這樣動態(tài)鏈接庫的容積會比較?。。┩瓿?dll 文件的編譯后,就可以在 Java 中調(diào)用 C 程序中的方法了。例如文件 test.javapublic class test public test() public static void main(String args) byte mobileno = 0 x31, 0 x33, 0 x36, 0 x36, 0 x31, 0 x36, 0 x33, 0 x30, 0 x36, 0 x36, 0

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論