JNI 函式命名
我想應該很多Android App 程式設計師會使用 JNI (Java Native Interface) , 但本篇文章不著重在 JNI 本身, 而是著重在 JNI 函式命名. 以 PACKAGE "com.example.gltest" , Class "MainActivity" 下面的 java code (MainActivity.java) 為例:
假設 JNI 函式為 nativePlay(),
... public class MainActivity { static { System.loadLibrary("NativeClient"); public native long nativePlay(int on); .... } ...
C++ 相對應之函式命名 應該是:
extern "C" JNIEXPORT void Java_com_example_gltest_MainActivity_nativePlay(JNIEnv *env, jobject obj, jint on);
其中 com_example_gltest 代表 Package name, MainActivity 代表 Class name, nativePlay 則是 Instance method .
可以有一致的命名方式嗎?
筆者這裡有一個自己發明的小方法, 提供大家做為參考. 同樣地我們假設 package 名稱為 com.example.gltest.MainActivity 裡面有一 JNI method 是:
public native int nativePlay(int on);
我的方法是:
1. 相對應的 native header 定義:
... #define CLASS com_example_gltest_MainActivity #define _CLASS "com/example/gltest/MainActivity" ...
2. 相對應的 native header 定義使用巨集
... #define NAME3(CLASS3, FUNC3) Java_ ## CLASS3 ## _ ##native## FUNC3 #define NAME2(CLASS2, FUNC2) NAME3(CLASS2, FUNC2) #define NAME(FUNC) NAME2(CLASS, FUNC) ...
3. 相對應的 native header 定義 nativePlay
... #define nativePlay NAME(Play) ... #if defined(__cplusplus) || defined(__CPLUSPLUS__) extern "C" { #endif // __CPLUSPLUS__ JNIEXPORT jint nativePlay(JNIEnv *env, jobject obj, jint on); #if defined(__cplusplus) || defined(__CPLUSPLUS__) } #endif //__CPLUSPLUS__ ...
4. 相對應的 native CPP 實做 nativePlay
... jint nativePlay(JNIEnv *env, jobject obj, jint on) { ... //return app->Play(on); return 0; } ...
如何? 應該還不錯吧?
如果你把上述巨集展開來, 可以得到:
JNIEXPORT void Java_com_example_gltest_MainActivity_nativePlay(JNIEnv *env, jobject obj, jint on);
與我們預期得一致. package 名稱改變時只要修改 CLASS 以及 _CLASS 的定義即可 (方便吧? ).
讀者可以參考 Android Studio 2.2.1 External Tools (ndkBuild) 這篇文章.
Static Method
如果說宣告為 static, for example,
...
public class MainActivity {
static { System.loadLibrary("NativeClient");
public static native long nativePlay(int on);
....
}
...
則上述所有的參數 jobject obj , 請改為 jclass cls.
在 Header 定義 #define _CLASS 是做什麼用的?
是做為 CallVoidMethod() 用的. 這我日後再做說明.
...
// in C compiler
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
...
or
...
// in C++ compiler
jniEnv->CallVoidMethod(mTestProvider, sayHello,jstrMSG);
...
為什麼要一致的命名方式嗎?
很簡單的原因. 讓您或他人在閱讀你的 java 原始碼時不會因為 JNI 而造成閱讀的斷點.
Email: jasonc@mail2000.com.tw
留言列表