android windows 上JNI編程,androidjni
昨天學習windows上的JNI編程,JNI說白了就是java和c語言的一個互相溝通的橋樑,java可以調用JNI來完成調用C語言實現的方法。JNI的全稱是(Java native interface),其實在編程重你只需要將與java互動的函數寫出來,其他的C語言內部調用的就可以直接使用C語言相關文法了。閑話少說,開始正題吧。要想在windroid或者是linux上使用JNI必須要下載NDK的並且指定路徑,在windows我們還需要安裝一個sygwin,這裡我就不再說怎樣安裝cygwin了,在你安裝好的cygwin檔案夾中找到一個etc的檔案夾,在這個檔案中找到一個profile檔案,修改其中的Path後加上:(ndk的路徑),在我理解ndk就是構建出了一個重pc到android的一個交叉編譯環境,當然它裡面還有很多我不知道的,還有待探索。然後我們就可以開始使用了,當然你要是用eclipse寫C/C++還需要安裝cdt外掛程式。安裝過後就可以使用eclipse編寫c/c++的代碼了。下面我們來看看代碼怎樣編寫吧,首先我們在android工程中建立一個jni的檔案夾,在jni的檔案夾中建立c語言的源檔案,在android中穿件一個類,類中可以使用native標識建立函數例如下面:public class DataProvider { //帶參數的c語言調用java語言 public int add2( int x, int y){ return x + y; } //無參數的函數C語言調用java語言 public void show(){ System.out.println( "我被調用了啊" ); } //無參數的靜態函數C語言調用java語言 public static void show2(){ System.out.println( "我又被調用了啊" ); } //將函數使用native標識,可以自動產生相應的函數 public native int add(int x, int y); public native int sayHello( String hello ); public native int[] array(int[] arr); public native int callbackadd2(); public native void callbackshow(); public native static void callbackshow2(); public native void callbackshow3();}
將這個類寫好了就可以使用javah (類的全類名), 全類名是指包名+類名,例如com.example.testjni.DataProvider,這樣就可以產生一個c語言中使用的標頭檔例如:/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_testjni_DataProvider */#ifndef _Included_com_example_testjni_DataProvider#define _Included_com_example_testjni_DataProvider#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_testjni_DataProvider * Method: add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add (JNIEnv *, jobject, jint, jint);/* * Class: com_example_testjni_DataProvider * Method: sayHello * Signature: (Ljava/lang/String;)I */JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello (JNIEnv *, jobject, jstring);/* * Class: com_example_testjni_DataProvider * Method: array * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array (JNIEnv *, jobject, jintArray);/* * Class: com_example_testjni_DataProvider * Method: callbackadd2 * Signature: ()I */JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2 (JNIEnv *, jobject);/* * Class: com_example_testjni_DataProvider * Method: callbackshow * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow (JNIEnv *, jobject);/* * Class: com_example_testjni_DataProvider * Method: callbackshow2 * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2 (JNIEnv *env, jclass);/* * Class: com_example_testjni_DataProvider * Method: callbackshow3 * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif這些都是使用javah後自動產生的。下一步我將該在c語言中是實現這些函數了,在此之前還需要建立一個mk檔案,這個檔案就是makefile,C語言在編譯成庫的情況下就可以讀取makefile來編譯。mk檔案: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #對應的c語言的函數庫 LOCAL_MODULE := hello #對應c代碼的檔案 LOCAL_SRC_FILES := hello.c functions.c LOCAL_LDLIBS := -llog//使用本地庫 include $(BUILD_SHARED_LIBRARY)
#include <stdio.h>#include "com_example_testjni_DataProvider.h" //引用標頭檔#include <android/log.h> //列印的日誌const char *TAG = "clog";#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__ );#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__ );//使用log標頭檔中的函數列印日誌到eclipse中的logcat,在這裡需要在mk檔案中添加庫引用,LOCAL_LDLIBS += -llogJNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add (JNIEnv *env, jobject o, jint x, jint y){ LOGI("%d\n", x ); LOGD("%d\n", y ); return x + y; //直接返回就可以}//int print(jintArray localarray, int i);int print( int* localarray, int i ){ LOGD( "array = %d\n", *(localarray+i)); return 0;}//平常的c語言代碼,可以直接調用/* * Class: com_example_testjni_DataProvider * Method: sayHello * Signature: (Ljava/lang/String;)I */JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello (JNIEnv *env, jobject o, jstring hello){}/* * Class: com_example_testjni_DataProvider * Method: array * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array (JNIEnv *env, jobject obj, jintArray array )//傳的是一個java中int型數組,java調用c語言{ //獲得數組長度 int length = (*env)->GetArrayLength(env, array); int i; jint* localarray = (*env)->GetIntArrayElements(env, array, 0); for( i = 0; i < length; i++ ){ *(localarray+i) += 5; print( localarray, i ); } return array;}/* * Class: com_example_testjni_DataProvider * Method: callbackadd2 * Signature: ()I */JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2 (JNIEnv *env, jobject obj){ jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetMethodID(env, clazz, "add2", "(II)I"); return (*env)->CallIntMethod(env, obj, mid, 3, 5);}/* * Class: com_example_testjni_DataProvider * Method: callbackshow * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow (JNIEnv *env, jobject obj){ jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetMethodID(env, clazz, "show", "()V");// (*env)->CallVoidMethod(env, obj, mid);}/* * Class: com_example_testjni_DataProvider * Method: callbackshow2 * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2 (JNIEnv *env, jclass jc){ jmethodID mid = (*env)->GetStaticMethodID(env, jc, "show2", "()V"); jobject obj = (*env)->CallStaticObjectMethod(env, jc, mid); (*env)->CallVoidMethod(env, obj, mid);}/* * Class: com_example_testjni_DataProvider * Method: callbackshow3 * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *env, jobject obj){ jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V"); (*env)->CallVoidMethod(env, obj, mid);}java調用C語言將java傳過來的值,使用jni的方法進行處理,然後使用,返回,c語言調用java需要在C語言代碼中進行映射,例如:JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *env, jobject obj){ jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");//得到類的位元組碼 jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V");//得到函數的id (*env)->CallVoidMethod(env, obj, mid);//執行函數}執行函數有不同的call函數,例如返回值是int是CallIntMethod(env, obj, mid, 3, 5);空類型是CallVoidMethod(env, obj, mid);後面的()V是函數簽名,代表是返回值是void型,無參的函數。(II)I返回值是int型參數是兩個int值得函數。c語言編寫後要在工程的src目錄下運行ndk-bulid命令就可以產生一個c語言庫,在eclipse工程目錄中也有顯示。在每次編譯之前需要刪除obj檔案夾,以清除緩衝。jni對於一些可以很大的提高java代碼的隱秘性,而且使用c語言開發jni程式可以提高效率。