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 而造成閱讀的斷點. 

 

 

 


 

 

 

z.png
Email: jasonc@mail2000.com.tw

 

 

 

 

 

 

arrow
arrow
    創作者介紹
    創作者 Lexra 的頭像
    Lexra

    Lexra Pixnet

    Lexra 發表在 痞客邦 留言(0) 人氣()