JNI環境的支援
Android JNI程式設計從Java方法來調用native方法是比較容易的,
因為Java本身就提供了native關鍵字作為索引,隻要正确的對應Java方法和native方法的包名,做到這一步并不難.
而從C/C++方法調用Java方法則稍複雜一點,因為C/C++沒有提供跨語言調用的直接支援,是以需要由Java的JNI運作環境來提供幫助.
每一個JNI native方法的聲明一般是這樣的:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_sliver_cx_android_1test_MainActivity_stringFromJNI(JNIEnv *env,jobject);
一個個關鍵字的作用是:
extern "C" C/C++的聲明關鍵字 表明這個jni方法是按照C的文法進行編譯的.
JNIEXPORT 在jni的固件代碼中這樣聲明
#define JNIEXPORT __attribute__ ((visibility ("default")))
visibility ("default")意味着GCC在生成動态庫的時候 預設這個方法的符号是被隐藏的
這樣做應該是為了除了這個apk外不讓其他程式使用這個庫的這個方法
Java_com_sliver_cx_android_1test_MainActivity_stringFromJNI
jni方法名:命名格式 包名_方法名 anroid_1test這個數字似乎是ide自己加上的 實際上在調用FindClass尋找class時,不應該帶有這個
JNIEnv *env,jobject
JNI方法的預設參數 env是JNI的運作環境 jobject是調用這個native方法的Java類
Java簽名
Java方法是帶有簽名的,而C/C++ native方法要調用Java方法 需要知道Java方法的簽名.
在terminal下:
首先編譯出class檔案
javac test.java
執行 javap -s test可以輸出類test中方法的簽名
簽名對應規則 void call(); 對應 ()V
括号内是參數簽名 括号後是傳回值簽名 V對應void
引申出的多個參數簽名 void call(int a); 對應 (I)V
int call(int a, char b);對應 (IC)I
JNI api
FindClass()
函數原型
jclass FindClass(const char* name)
{
return functions->FindClass(this, name);
}
FindClass用來尋找在JNI環境中的Java Class
name為指定的包名
例如 FindClass("com/cx/test/Test"); // com/cx/test是包名 Test是類名
GetMethod
函數原型
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
{ return functions->GetMethodID(this, clazz, name, sig); }
GetMethod用來尋找JNI環境中的java類的方法
clazz為調用這個native方法的Java類
name為尋找的Java方法名
sig為Java方法的簽名
例如 GetMethod(obj, "call", "()V");
應用舉例
Java class:
public class Test {
public void call(int nb) {
System.out.println("cnt" + nb);
}
public native test_call();
}
調用 Java Class:
public class Call {
public static void main(String[] args) {
Test a = new Test();
a.test_call();
}
}
JNI cpp:
extern "C"
JNIEXPORT void JNICALL
Java_com_cx_test_Test_call(
JNIEnv *env,
jobject obj,
int cnt) {
jclass myclass = env->FindClass("com/cx/test/Test");
if (myclass == nullptr) {
LOGI("failed to find class");
return;
}
jmethodID myid = env->GetMethodID(myclass, "call", "(I)V");
if (myid == nullptr) {
LOGI("failed to get method id");
return;
}
env->CallVoidMethod(obj, myid, );
}