標籤:android ndk
這篇已經是"一步一步學習androidNDK編程"的第四篇了,在這篇中,我們將會在java中傳遞代碼給c代碼。
首先,我們建立一個android工程"ndkdata",
第一步:
同樣的首先聲明native方法,如下:
public native int add(int a,int b);public native String helloSir(String name);public native int[] intMethod(int[] intArray);
可以看到我這裡聲明了三個方法,用來傳遞不同的資料類型給c代碼
第二步:
由於我們的這些方法都是聲明在MainActivity.java中的,所以我們需要首先將該MainActivity.java用javac編譯為.class檔案,然後運用javah,產生對應的.h標頭檔。
將該MainActivity.java用javac編譯為.class檔案:這個就是運行該android工程即可在bin/classes目錄下產生對應的.class檔案。
命令列下進入bin/classes所在的目錄:執行javah com.example.ndkdata.MainActivity即可在該目錄下產生對應的com_example_ndkdata_MainActivity.h標頭檔了,內容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_ndkdata_MainActivity */#ifndef _Included_com_example_ndkdata_MainActivity#define _Included_com_example_ndkdata_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_ndkdata_MainActivity * Method: add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add (JNIEnv *, jobject, jint, jint);/* * Class: com_example_ndkdata_MainActivity * Method: helloSir * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir (JNIEnv *, jobject, jstring);/* * Class: com_example_ndkdata_MainActivity * Method: intMethod * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod (JNIEnv *, jobject, jintArray);#ifdef __cplusplus}#endif#endif 接下來我們在ndkdata工程中,建立jni目錄,然後再將剛才產生的com_example_ndkdata_MainActivity.h檔案拷貝到該目錄下,然後建立我們的c代碼:hello.c
將com_example_ndkdata_MainActivity.h中產生的方法添加到hello.c檔案中這裡需要添加參數,因為預設產生的只有方法的參數類型,沒有參數對象,並且引入對應的標頭檔,如下:
#include<stdio.h>#include<jni.h>#include "com_example_ndkdata_MainActivity.h"JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add (JNIEnv * env, jobject obj, jint x, jint y) { }JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir (JNIEnv * env, jobject obj, jstring jstr) { }JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod (JNIEnv * env, jobject obj, jintArray arr) { }接下來就是實現我們的c代碼了,如下:
#include<stdio.h>#include<jni.h>#include "com_example_ndkdata_MainActivity.h"JNIEXPORT jint JNICALL Java_com_example_ndkdata_MainActivity_add (JNIEnv * env, jobject obj, jint x, jint y) { return x+y; }/** * 傳回值 char* 這個代表char數組的首地址 * Jstring2CStr 把java中的jstring的類型轉化成一個c語言中的char 字串 */char* Jstring2CStr(JNIEnv* env, jstring jstr){<span style="white-space:pre"></span> char* rtn = NULL;<span style="white-space:pre"></span> jclass clsstring = (*env)->FindClass(env,"java/lang/String"); //String<span style="white-space:pre"></span> jstring strencode = (*env)->NewStringUTF(env,"GB2312"); // 得到一個java字串 "GB2312"<span style="white-space:pre"></span> jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");<span style="white-space:pre"></span> jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");<span style="white-space:pre"></span> jsize alen = (*env)->GetArrayLength(env,barr); // byte數組的長度<span style="white-space:pre"></span> jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);<span style="white-space:pre"></span> if(alen > 0)<span style="white-space:pre"></span> {<span style="white-space:pre"></span> rtn = (char*)malloc(alen+1); //"\0"<span style="white-space:pre"></span> memcpy(rtn,ba,alen);<span style="white-space:pre"></span> rtn[alen]=0;<span style="white-space:pre"></span> }<span style="white-space:pre"></span> (*env)->ReleaseByteArrayElements(env,barr,ba,0); //<span style="white-space:pre"></span> return rtn;}JNIEXPORT jstring JNICALL Java_com_example_ndkdata_MainActivity_helloSir (JNIEnv * env, jobject obj, jstring jstr) { //在c語言中 是沒有java的String<span style="white-space:pre"></span>char* cstr = Jstring2CStr(env, jstr);<span style="white-space:pre"></span>// c語言中的字串 都是以'\0' 作為結尾<span style="white-space:pre"></span>char arr[7]= {' ','h','e','l','l','o','\0'};<span style="white-space:pre"></span>strcat(cstr,arr);<span style="white-space:pre"></span>return (*env)->NewStringUTF(env,cstr); }JNIEXPORT jintArray JNICALL Java_com_example_ndkdata_MainActivity_intMethod (JNIEnv * env, jobject obj, jintArray arr) { }
編寫完了hello.c之後,需要編寫Android.mk,內容如下:
#交叉編譯編譯c/c++代碼所依賴的設定檔#擷取當前Android.mk的路徑 LOCAL_PATH := $(call my-dir)#變數初始化操作include $(CLEAR_VARS)#libhello.so 其實產生的libhello.so就是在我們這個模組的名稱前面加上lib後邊加上.soLOCAL_MODULE := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)
現在就需要在cygwine的命令列下進入該工程ndkdata的根目錄下,執行"ndk-build"命令產生對應的可直接啟動並執行二進位檔案,注意每次在執行"ndk-build"之後最好將android工程clean一下。
在“ndk-build”成功之後,需要在java代碼中引入這些庫檔案:
static { System.loadLibrary("hello");}
注意這裡的"hello",就是我們在Android.mk檔案中寫的模組名,即LOCAL_MODULE的值。
現在,就可以執行聲明的native方法了,在java代碼中直接調用即可,是不是很簡單呢。
源碼下載
一步一步學習androidNDK編程(java給c傳遞資料)