一、靜態註冊
- 原理:
- 根據函數名來建立 java 方法與 JNI 函數的一一對應關係;
- 以Java爲前綴,並且用“_”下劃線,將包名、類名以及native方法名連接起來;
- 實現流程:
- 編寫 java 代碼;
- 利用 javah 指令生成對應的 c 文件;
- 對 c 文件中的聲明進行實現;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
二、動態註冊
- 原理:
- 利用 RegisterNatives 方法來註冊 java 方法與 JNI 函數的一一對應關係;
- 實現流程:
- 利用結構體 JNINativeMethod 數組記錄 java 方法與 JNI 函數的對應關係;
- 實現 JNI_OnLoad 方法,在加載動態庫後,執行動態註冊;
- 調用 FindClass 方法,獲取 java 對象;
- 調用 RegisterNatives 方法,傳入 java 對象,以及 JNINativeMethod 數組,以及註冊數目完成註冊;
public class JniUtils {
static {
System.loadLibrary("native-lib");
}
public static native String stringFromJNI();
public static native int calculateByJNI(int count);
}
#include <jni.h>
#include <string>
// 指定要註冊的類
#define JNIREG_CLASS "com/example/jnilibrary/JniUtils"
// 指定代碼所在的段。在編譯時,把該函數編譯到自定義的section裏。
// 由於在java層沒有定義該函數,因此需要寫到一個自定義的section裏。
extern "C"
__attribute__((section(".mysection"))) JNICALL jstring getStr1(JNIEnv *env, jobject obj) {
return env->NewStringUTF("Hello from C++");
}
extern "C"
__attribute__((section(".mysection"))) JNICALL jint getInt1(JNIEnv *env, jobject obj, jint count) {
return (count + 1);
}
// 第一個參數:Java層的方法名
// 第二個參數:方法的簽名,括號內爲參數類型,後面爲返回類型
// 第三個參數:需要重新註冊的方法名
static JNINativeMethod getMethods[] = {
{"stringFromJNI", "()Ljava/lang/String;", (void *) getStr1},
{"calculateByJNI", "(I)I", (void *) getInt1}
};
extern "C"
int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *getMethods,
int numMethods) {
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, getMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
extern "C"
int registerNatives(JNIEnv *env) {
if (!registerNativeMethods(env, JNIREG_CLASS, getMethods,
sizeof(getMethods) / sizeof(getMethods[0]))) {
return JNI_FALSE;
}
return JNI_TRUE;
}
extern "C"
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
if (!registerNatives(env)) {
return -1;
}
return JNI_VERSION_1_6;
}