2015年3月18日 星期三

[Android] 如何藉由JNI來呼叫底層Native的C/C++程式 - part I

基本上,Android提供的API已足夠一般寫程式的需求,
不過,有時候我們仍然會需要直接呼叫底層Native的C/C++程式,
有時是因為效能,有時是因為Android提供的功能不足...

如果你也是使用Eclipse,
那麼,你必須先安裝CDT和NDK,
之後,在你想要增加JNI介面的project按右鍵,
執行"Android Tools"/"Add Native Support"後,
你會發現project下面多了一個"jni"目錄,
目錄底下還有一個"x.cpp"和"Android.mk",
到這邊,你已經完全了第一步了...

接下來,Java要如何呼JNI的函式呢?

package myTest.com;
 
import android.app.Activity;
import android.os.Bundle;
 
public class MainActivity extends Activity { 
 private native String hello(String s); 
 
 static {
  System.loadLibrary("NativeMyTest");
 } 
}
"NativeMyTest"是你剛剛產生jni目錄時,輸入的名稱,
也就是說,待會會產生NativeMyTest.so檔,
 hello(String s)則是定義在JNI裡的函式,
 那JNI這邊呢?
#include <jni.h>
#include <stdio.h>

 #define LOG_TAG "MainActivity"
#define LOGI(...) __android_log_print(4, LOG_TAG, __VA_ARGS__);

JNIEXPORT void hello(JNIEnv* env, jobject obj, jstring str){ 
 LOGI("hello: %s", str);
}

jint JNI_OnLoad(JavaVM* pVm, void* reserved) {
  JNIEnv* env;
  if ((*pVm)->GetEnv(pVm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) {
  return -1;
  }
 
  JNINativeMethod nm[2];
  nm[0].name = "hello";
  nm[0].signature = "(Ljava/lang/String)V";
  nm[0].fnPtr = (void*)hello;

  jclass cls = (*env)->FindClass(env, "myTest/com/MainActivity");
  (*env)->RegisterNatives(env, cls, nm, 1);
  gJavaVM = pVm;
  return JNI_VERSION_1_6;
}
JNI_OnLoad()是用來載入那些會被Java程式所呼叫的函式,
FindClass()傳入的參數必須和Java程式的package和class名稱一樣,
執行時,看看是載入NativeMyTest.so有問題,還是沒有發現hello函式,
再來決定是那裡有問題...

沒有留言:

張貼留言