android調用so
android虛擬機器不能直接調用底層裝置,我們如果要對底層裝置進行調用就需要用到so.
so使用C語言或C++編寫完成,使用ndk進行編譯,直接運行在linux核心中.
按jni調用so時基本類型可以直接互動,jstring使用時有點麻煩,所以我做一個jstring和char*進行轉換的例子.
第一步:
工程根目錄下建立jni目錄.libs目錄不用手動建立.
注意:這裡使用ndk_R7所以不需要用jdk去產生C檔案頭.
第二部:
java編寫介面檔案(Device.java)
[java] view plain copy public class Device { static { System.loadLibrary("device"); } public native String deviceTestString(String test); } 方法名必須使用native關鍵字聲明,並且必須使用system.loadLibrary("SO檔案名稱")承載c類庫;
第三部:
編寫C檔案(devices.c)
這裡編寫的c代碼屬於linux C範疇.
[cpp] view plain copy #include <string.h> #include <jni.h> char* jstringTostrM(JNIEnv* env, jstring jstr) { char* pStr = NULL; jclass jstrObj = (*env)->FindClass(env, "java/lang/String"); jstring encode = (*env)->NewStringUTF(env, "utf-8"); jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode); jsize strLen = (*env)->GetArrayLength(env, byteArray); jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE); if (jBuf > 0) { pStr = (char*)malloc(strLen + 1); if (!pStr) { return NULL; } memcpy(pStr, jBuf, strLen); pStr[strLen] = 0; } (*env)->ReleaseByteArrayElements(env, byteArray, jBuf, 0); return pStr; } jstring Java_com_jack_Device_deviceTestString(JNIEnv* env,jclass clazz,jstring path){ //system("echo devices.so test > /sdcard/log/log.txt"); char * test = jstringTostrM(env,path); return (*env)->NewStringUTF(env, test); }
注意:C的函數命名規則:Java是jni標準必須有,com_jack_Device是Device.java檔案的全名,再下來才是C函數名
jstringTostrM函數必須寫在Java_com_jack_Device_deviceTestString函數前,如果不是必須要C檔案開頭進行聲明.
聲明代碼:
[cpp] view plain copy char* jstringTostrM(JNIEnv* env, jstring jstr); 第四步:編寫Android.mk和編譯
android.mk檔案如下: