1. 程式人生 > >jni 開發 c呼叫java

jni 開發 c呼叫java

上一篇文章是java如何呼叫c ,這篇文章是c如何呼叫 java 

c呼叫java一共分為5步:

1:編寫java native方法

2生成對應的標頭檔案

3複製標頭檔案到visule studio中

4查詢方法和屬性的簽名,實現native方法

5編譯生成.dll動態庫,複製動態庫到專案,然後呼叫

1:編寫java native方法 以及要呼叫的方法

	public native int ranNum();


//產生隨機數  要被native呼叫的方法
public int getRandomNum(int max) {
return (new Random()).nextInt(max);
}

2生成對應的標頭檔案    在當前src目錄下 使用命令列執行javah ,然後重新整理專案,後會有標頭檔案



3複製標頭檔案到visule studio中

開啟visual studio 建立新專案,把  jni.h  jni_md.h(這兩個檔案在AndroidSDK中)以剛才及java工程生成的 com_ake_Test_test.h標頭檔案一起拷貝到visual studio中

標頭檔案右鍵->新增->現有項,之後如下圖


4查詢方法和屬性的簽名,實現native方法

在命令列中  java專案的bin 目錄下執行javap 命令,然後在執行javap -s -p com.ake.Test.test(類的全名)


執行完javap -s -p之後如圖  系統會把當前類所有的成員變數和屬性方法的簽名都列出來


在這個列表中我們找到

  public int getRandomNum(int);
    descriptor: (I)I
這個方法的簽名就是   (I)I

然後開啟visual studio 把java 生成的標頭檔案複製進來


然後就是寫個str.c 檔案實現這個方法


5編譯生成.dll動態庫,複製動態庫到專案,然後呼叫

在 Visual studio 中 

選擇工具欄中 debug--配置管理器--活動解決方案平臺--新建--選擇新平臺--x64(我的電腦是64位)

配置專案生成.dll動態連結庫

專案右鍵--常規--專案預設值--配置型別--動態庫(.dll)

最後執行生成解決方法,然後複製根目錄x64 --debug--.dll到java工程根目錄

java呼叫  System.load("D:\\Android\\workspace3\\JniTest\\Project2.dll");  這裡要寫絕對路徑

這是個基本流程, 同樣訪問 c 訪問java的成員變數也是一樣的流程,只是在c程式碼的實現是不一樣的

//c 訪問java 成員屬性的實現

JNIEXPORT jstring JNICALL Java_com_ake_Test_test_accessStaticField (JNIEnv *env, jobject obj){ //1 獲取obj物件 jclass cls=(*env)->GetObjectClass(env, obj); //2獲取屬性id jfieldID id=(*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;"); // printf("jstr:%#x\n", &id); //獲取屬性值 jstring js=(*env)->GetObjectField(env, obj,id); // printf("jstr:%#x\n", &js); char * ori=(*env)->GetStringUTFChars(env, js, JNI_FALSE); // printf("new_jstr:%s\n", ori); //修改屬性值 char* test = "mimi"; strcat(test,ori); //設定屬性值 jstring s = (*env)->NewStringUTF(env, test); (*env)->SetObjectField(env, obj,id,s); return ori; }

// c訪問 java 方法的實現

JNIEXPORT jint JNICALL Java_com_ake_Test_test_ranNum (JNIEnv *env, jobject obj){ //獲取class 物件 jclass cls= (*env)->GetObjectClass(env, obj); //獲取方法ID 最後一個引數是我們在命令列中查到的方法的簽名 jmethodID id= (*env)->GetMethodID(env, cls, "getRandomNum", "(I)I"); //呼叫該方法 jint i=(*env)->CallIntMethod(env, obj, id); return i; }

他們的實現套路是一樣的:

1獲取jclass 物件

2獲取 方法或者屬性 id

3獲取方法或者屬性 

4修改成員的值或返回方法的值

這獲取方法或者屬性想id時要求傳入 簽名  sign  下圖有對應關係  如果想偷懶就用命令列在 java bin目錄下 javap /javap -s -p看一xia

成員屬性的簽名可以直接抄就行了,方法的簽名格式  (type)type  也就是  用()拼上引數的簽名和返回值的簽名  例如java 方法  

public static String getUUID(){
return UUID.randomUUID().toString();
}

簽名為  ()Ljava/lang/String;   

public static void soutsom(){
System.out.println("soutsom 被呼叫!");
}

簽名為 ()V


好了,謝謝大家能把它看完,有問題歡迎聯絡我!