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
好了,謝謝大家能把它看完,有問題歡迎聯絡我!