多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > JNI 實戰全面解析

JNI 實戰全面解析

來源:程序員人生   發布時間:2014-11-05 08:44:39 閱讀次數:4668次
簡介

項目決定移植1款C++開源項目到Android平臺,開始對JNI深入研究。

JNI是甚么?

JNI(Java Native Interface)意為JAVA本地調用,它允許Java代碼和其他語言寫的代碼進行交互,簡單的說,1種在Java虛擬機控制下履行代碼的標準機制。

NDK是甚么?

Android NDK(Native Development Kit )是1套工具集合,允許你用像C/C++語言那樣實現利用程序的1部份。

為何要用NDK?

1、安全性,java是半解釋型語言,很容易被反匯編后拿到源代碼文件,我們可以在重要的交互功能使用C語言代替。
2、效力,C語言比起java來講效力要高出很多。

JNI和NDK的區分?

從工具上說,NDK其實多了1個把.so和.apk打包的工具,而JNI開發并沒有打包,只是把.so文件放到文件系統的特定位置。
從編譯庫說NDK開發C/C++只能能使用NDK自帶的有限的頭文件,而使用JNI則可使用文件系統中帶的頭文件。
從編寫方式說,它們1樣。

詳解
1、JNI 元素

1、JNI組織結構


JNI函數表的組成績像C++的虛函數表,虛擬機可以運行多張函數表。
JNI接口指針僅在當前線程中起作用,指針不能從1個線程進入另外一個線程,但可以在不同的線程中調用本地方法。


2、原始數據

Jobject  對象 援用類型


Java類型 本地類型(JNI) 描寫
boolean(布爾型)jboolean 無符號8個比特
byte(字節型)jbyte 有符號8個比特
char(字符型)jchar 無符號16個比特
short(短整型)jshort 有符號16個比特
int(整型)jint 有符號32個比特
long(長整型)jlong 有符號64個比特
float(浮點型)jfloat 32個比特
double(雙精度浮點型)jdouble 64個比特
void(空型)void N/A

函數操作

函數 Java 數組類型 本地類型 說明
GetBooleanArrayElementsjbooleanArrayjbooleanReleaseBooleanArrayElements 釋放
GetByteArrayElementsjbyteArrayjbyteReleaseByteArrayElements 釋放
GetCharArrayElementsjcharArrayjcharReleaseShortArrayElements 釋放
GetShortArrayElementsjshortArrayjshortReleaseBooleanArrayElements 釋放
GetIntArrayElementsjintArrayjintReleaseIntArrayElements 釋放
GetLongArrayElementsjlongArrayjlongReleaseLongArrayElements 釋放
GetFloatArrayElementsjfloatArrayjfloatReleaseFloatArrayElements 釋放
GetDoubleArrayElementsjdoubleArrayjdoubleReleaseDoubleArrayElements 釋放
GetObjectArrayElement自定義對象object 
SetObjectArrayElement自定義對象object 
GetArrayLength  獲得數組大小
New<Type>Array  創建1個指定長度的原始數據類型的數組
GetPrimitiveArrayCritical  得到指向原始數據類型內容的指針,該方法可能使垃圾回收不能履行,該方法可能返回數組的拷貝,因此必須釋放此資源。
ReleasePrimitiveArrayCritical  釋放指向原始數據類型內容的指針,該方法可能使垃圾回收不能履行,該方法可能返回數組的拷貝,因此必須釋放此資源。
NewStringUTF  jstring類型的方法轉換
GetStringUTFChars  jstring類型的方法轉換
DefineClass   從原始類數據的緩沖區中加載類
FindClass   該函數用于加載本地定義的類。它將搜索由CLASSPATH 環境變量為具有指定名稱的類所指定的目錄和 zip文件
GetObjectClass   通過對象獲得這個類。該函數比較簡單,唯1注意的是對象不能為NULL,否則獲得的class肯定返回也為NULL
GetSuperclass   獲得父類或說超類 。 如果 clazz 代表類class而非類 object,則該函數返回由 clazz 所指定的類的超類。 如果 clazz指定類 object 或代表某個接口,則該函數返回NULL
IsAssignableFrom   肯定 clazz1 的對象是不是可安全地強迫轉換為clazz2
Throw  拋出 java.lang.Throwable 對象
ThrowNew   利用指定類的消息(由 message 指定)構造異常對象并拋出該異常
ExceptionOccurred   肯定是不是某個異常正被拋出。在平臺相干代碼調用 ExceptionClear() 或 Java 代碼處理該異常前,異常將始終保持拋出狀態
ExceptionDescribe   將異常及堆棧的回溯輸出到系統毛病報告信道(例如 stderr)。該例程可便利調試操作
ExceptionClear   清除當前拋出的任何異常。如果當前無異常,則此例程不產生任何效果
FatalError   拋出致命毛病并且不希望虛擬機進行修復。該函數無返回值
NewGlobalRef   創建 obj 參數所援用對象的新全局援用。obj 參數既可以是全局援用,也能夠是局部援用。全局援用通過調用DeleteGlobalRef() 來顯式撤銷。
DeleteGlobalRef   刪除 globalRef 所指向的全局援用
DeleteLocalRef   刪除 localRef所指向的局部援用
AllocObject   分配新 Java 對象而不調用該對象的任何構造函數。返回該對象的援用。clazz 參數務必不要援用數組類。
getObjectClass  返回對象的類
IsSameObject  測試兩個援用是不是援用同1 Java 對象
NewString   利用 Unicode 字符數組構造新的 java.lang.String 對象
GetStringLength   返回 Java 字符串的長度(Unicode 字符數)
GetStringChars   返回指向字符串的 Unicode 字符數組的指針。該指針在調用 ReleaseStringchars() 前1直有效
ReleaseStringChars   通知虛擬機平臺相干代碼無需再訪問 chars。參數chars 是1個指針,可通過 GetStringChars() 從 string 取得
NewStringUTF   利用 UTF⑻ 字符數組構造新 java.lang.String 對象
GetStringUTFLength   以字節為單位返回字符串的 UTF⑻ 長度
GetStringUTFChars   返回指向字符串的 UTF⑻ 字符數組的指針。該數組在被ReleaseStringUTFChars() 釋放前將1直有效
ReleaseStringUTFChars   通知虛擬機平臺相干代碼無需再訪問 utf。utf 參數是1個指針,可利用 GetStringUTFChars() 取得
NewObjectArray   構造新的數組,它將保存類 elementClass 中的對象。所有元素初始值均設為 initialElement
Set<PrimitiveType>ArrayRegion  將基本類型數組的某1區域從緩沖區中復制回來的1組函數
GetFieldID   返回類的實例(非靜態)域的屬性 ID。該域由其名稱及簽名指定。訪問器函數的
Get<type>Field 及 Set<type>Field系列使用域 ID 檢索對象域。GetFieldID() 不能用于獲得數組的長度域。應使用GetArrayLength()。
Get<type>Field  該訪問器例程系列返回對象的實例(非靜態)域的值。要訪問的域由通過調用GetFieldID() 而得到的域 ID 指定。 
Set<type>Field  該訪問器例程系列設置對象的實例(非靜態)屬性的值。要訪問的屬性由通過調用
SetFieldID() 而得到的屬性 ID指定。
GetStaticFieldID 

GetStatic<type>Field

SetStatic<type>Field
  同上,只不過是靜態屬性。
GetMethodID  返回類或接口實例(非靜態)方法的方法 ID。方法可在某個 clazz 的超類中定義,也可從 clazz 繼承。該方法由其名稱和簽名決定。 GetMethodID() 可以使未初始化的類初始化。要取得構造函數的方法 ID,應將<init> 作為方法名,同時將void (V) 作為返回類型。
CallVoidMethod   
CallObjectMethod   
CallBooleanMethod    
CallByteMethod   
CallCharMethod   
CallShortMethod   
CallIntMethod   
CallLongMethod   
CallFloatMethod   
CallDoubleMethod   
GetStaticMethodID   調用靜態方法
Call<type>Method   
RegisterNatives   向 clazz 參數指定的類注冊本地方法。methods 參數將指定 JNINativeMethod 結構的數組,其中包括本地方法的名稱、簽名和函數指針。nMethods 參數將指定數組中的本地方法數。
UnregisterNatives   取消注冊類的本地方法。類將返回到鏈接或注冊了本地方法函數前的狀態。該函數不應在常規平臺相干代碼中使用。相反,它可以為某些程序提供1種重新加載和重新鏈接本地庫的途徑。    
    

域描寫符

Java 語言
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
  

援用類型則為 L + 該類型類描寫符 + 。

數組,其為 :  [ + 其類型的域描寫符 + 。

多維數組則是 n個[ +該類型的域描寫符 , N代表的是幾維數組。

String類型的域描寫符為 Ljava/lang/String; [ + 其類型的域描寫符 + ; int[ ] 其描寫符為[I float[ ] 其描寫符為[F String[ ] 其描寫符為[Ljava/lang/String; Object[ ]類型的域描寫符為[Ljava/lang/Object; int [ ][ ] 其描寫符為[[I float[ ][ ] 其描寫符為[[F

 將參數類型的域描寫符依照申明順序放入1對括號中后跟返回值類型的域描寫符,規則以下: (參數的域描寫符的疊加)返回類型描寫符。對,沒有返回值的,用V(表示void型)表示。
舉例以下:

Java層方法 JNI函數簽名 String test ( ) Ljava/lang/String; int f (int i, Object object) (ILjava/lang/Object;)I void set (byte[ ] bytes) ([B)V

JNIEnv與JavaVM 

JNIEnv 概念 : 是1個線程相干的結構體, 該結構體代表了 Java 在本線程的運行環境 ; 

JNIEnv 與 JavaVM : 注意辨別這兩個概念; 
-- JavaVM : JavaVM 是 Java虛擬機在 JNI 層的代表, JNI 全局只有1個;
-- JNIEnv : JavaVM 在線程中的代表, 每一個線程都有1個, JNI 中可能有很多個 JNIEnv;

JNIEnv 作用 : 
-- 調用 Java 函數 : JNIEnv 代表 Java 運行環境, 可使用 JNIEnv 調用 Java 中的代碼;
-- 操作 Java 對象 : Java 對象傳入 JNI 層就是 Jobject 對象, 需要使用 JNIEnv 來操作這個 Java 對象;


JNIEnv 體系結構 

線程相干 : JNIEnv 是線程相干的, 即 在 每一個線程中 都有1個 JNIEnv 指針, 每一個JNIEnv 都是線程專有的, 其它線程不能使用本線程中的 JNIEnv, 線程 A 不能調用 線程 B 的 JNIEnv;

JNIEnv 不能跨線程 : 
-- 當前線程有效 : JNIEnv 只在當前線程有效, JNIEnv 不能在 線程之間進行傳遞, 在同1個線程中, 屢次調用 JNI層方法, 傳入的 JNIEnv 是相同的;
-- 本地方法匹配多JNIEnv : 在 Java 層定義的本地方法, 可以在不同的線程調用, 因此 可以接受不同的 JNIEnv;

JNIEnv 結構 : 由上面的代碼可以得出, JNIEnv 是1個指針,  指向1個線程相干的結構, 線程相干結構指向 JNI 函數指針 數組, 這個數組中寄存了大量的 JNI 函數指針, 這些指針指向了具體的 JNI 函數; 


注意:JNIEnv只在當前線程中有效。本地方法不能將JNIEnv從1個線程傳遞到另外一個線程中。相同的 Java 線程中對本地方法屢次調用時,傳遞給該本地方法的JNIEnv是相同的。但是,1個本地方法可被不同的 Java 線程所調用,因此可以接受不同的 JNIEnv。



UTF⑻編碼

JNI使用改進的UTF⑻字符串來表示不同的字符類型。Java使用UTF⑴6編碼。UTF⑻編碼主要使用于C語言,由于它的編碼用u000表示為0xc0,而不是通常的0×00。非空ASCII字符改進后的字符串編碼中可以用1個字節表示。

毛病

JNI不會檢查NullPointerException、IllegalArgumentException這樣的毛病,緣由是:致使性能降落。

在絕大多數C的庫函數中,很難避免毛病產生。
JNI允許用戶使用Java異常處理。大部份JNI方法會返回毛病代碼但本身其實不會報出異常。因此,很有必要在代碼本身進行處理,將異常拋給Java。在JNI內部,首先會檢查調用函數返回的毛病代碼,以后會調用ExpectOccurred()返回1個毛病對象。
jthrowable ExceptionOccurred(JNIEnv *env); 例如:1些操作數組的JNI函數不會報錯,因此可以調用ArrayIndexOutofBoundsException或ArrayStoreExpection方法報告異常。
3、JNI函數實戰

1、*.so的入口函數

JNI_OnLoad()與JNI_OnUnload()
當Android的VM(Virtual Machine)履行到System.loadLibrary()函數時,首先會去履行C組件里的JNI_OnLoad()函數。它的用處有2:
(1)告知VM此C組件使用那1個JNI版本。如果你的*.so檔沒有提供JNI_OnLoad()函數,VM會默許該*.so檔是使用最老的JNI 1.1版本。由于新版的JNI做了許多擴充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必須藉由JNI_OnLoad()函數來告知VM。
(2)由于VM履行到System.loadLibrary()函數時,就會立即先呼喚JNI_OnLoad(),所以C組件的開發者可以藉由JNI_OnLoad()來進行C組件內的早期值之設定(Initialization) 。


2、返回值

jstring str = env->newStringUTF("HelloJNI"); //直接使用該JNI構造1個jstring對象返回 return str ;
jobjectArray ret = 0; jsize len = 5; jstring str; string value("hello");   ret = (jobjectArray)(env->NewObjectArray(len, env->FindClass("java/lang/String"), 0)); for(int i = 0; i < len; i++) {     str = env->NewStringUTF(value..c_str());     env->SetObjectArrayElement(ret, i, str); } return ret; 返回數組
jclass m_cls = env->FindClass("com/ldq/ScanResult"); jmethodID m_mid = env->GetMethodID(m_cls,"<init>","()V"); jfieldID m_fid_1 = env->GetFieldID(m_cls,"ssid","Ljava/lang/String;"); jfieldID m_fid_2 = env->GetFieldID(m_cls,"mac","Ljava/lang/String;"); jfieldID m_fid_3 = env->GetFieldID(m_cls,"level","I"); jobject m_obj = env->NewObject(m_cls,m_mid); env->SetObjectField(m_obj,m_fid_1,env->NewStringUTF("AP1")); env->SetObjectField(m_obj,m_fid_2,env->NewStringUTF("00⑴1⑵2⑶3⑷4⑸5")); env->SetIntField(m_obj,m_fid_3,⑸0); return m_obj; 返回自定義對象

jclass list_cls = env->FindClass("Ljava/util/ArrayList;");//取得ArrayList類援用 if(listcls == NULL) { cout << "listcls is null " ; } jmethodID list_costruct = env->GetMethodID(list_cls , "<init>","()V"); //取得得構造函數Id jobject list_obj = env->NewObject(list_cls , list_costruct); //創建1個Arraylist集合對象 //或得Arraylist類中的 add()方法ID,其方法原型為: boolean add(Object object) ; jmethodID list_add = env->GetMethodID(list_cls,"add","(Ljava/lang/Object;)Z"); jclass stu_cls = env->FindClass("Lcom/feixun/jni/Student;");//取得Student類援用 //取得該類型的構造函數 函數名為 <init> 返回類型必須為 void 即 V jmethodID stu_costruct = env->GetMethodID(stu_cls , "<init>", "(ILjava/lang/String;)V"); for(int i = 0 ; i < 3 ; i++) { jstring str = env->NewStringUTF("Native"); //通過調用該對象的構造函數來new 1個 Student實例 jobject stu_obj = env->NewObject(stucls , stu_costruct , 10,str); //構造1個對象 env->CallBooleanMethod(list_obj , list_add , stu_obj); //履行Arraylist類實例的add方法,添加1個stu對象 } return list_obj ; 返回對象集合

3、操作Java層的類

//取得jfieldID 和 該字段的初始值 jfieldID nameFieldId ; jclass cls = env->GetObjectClass(obj); //取得Java層該對象實例的類援用,即HelloJNI類援用 nameFieldId = env->GetFieldID(cls , "name" , "Ljava/lang/String;"); //取得屬性句柄 if(nameFieldId == NULL) { cout << " 沒有得到name 的句柄Id ;" ; } jstring javaNameStr = (jstring)env->GetObjectField(obj ,nameFieldId); // 取得該屬性的值 const char * c_javaName = env->GetStringUTFChars(javaNameStr , NULL); //轉換為 char *類型 string str_name = c_javaName ; cout << "the name from java is " << str_name << endl ; //輸出顯示 env->ReleaseStringUTFChars(javaNameStr , c_javaName); //釋放局部援用 //構造1個jString對象 char * c_ptr_name = "I come from Native" ; jstring cName = env->NewStringUTF(c_ptr_name); //構造1個jstring對象 env->SetObjectField(obj , nameFieldId , cName); // 設置該字段的值
4、回調Java層方法

jstring str = NULL; jclass clz = env->FindClass("cc/androidos/jni/JniTest"); //獲得clz的構造函數并生成1個對象 jmethodID ctor = env->GetMethodID(clz, "<init>", "()V"); jobject obj = env->NewObject(clz, ctor); // 如果是數組類型,則在類型前加[,如整形數組int[] intArray,則對應類型為[I,整形數組String[] strArray對應為[Ljava/lang/String; jmethodID mid = env->GetMethodID(clz, "sayHelloFromJava", "(Ljava/lang/String;II[I)I"); if (mid) { LOGI("mid is get"); jstring str1 = env->NewStringUTF("I am Native"); jint index1 = 10; jint index2 = 12; //env->CallVoidMethod(obj, mid, str1, index1, index2); // 數組類型轉換 testIntArray能不能不申請內存空間 jintArray testIntArray = env->NewIntArray(10); jint *test = new jint[10]; for(int i = 0; i < 10; ++i) { *(test+i) = i + 100; } env->SetIntArrayRegion(testIntArray, 0, 10, test); jint javaIndex = env->CallIntMethod(obj, mid, str1, index1, index2, testIntArray); LOGI("javaIndex = %d", javaIndex); delete[] test; test = NULL; }

static void event_callback(int eventId,const char* description) { //主進程回調可以,線程中回調失敗。 if (gEventHandle == NULL) return; JNIEnv *env; bool isAttached = false; if (myVm->GetEnv((void**) &env, JNI_VERSION_1_2) < 0) { //獲得當前的JNIEnv if (myVm->AttachCurrentThread(&env, NULL) < 0) return; isAttached = true; } jclass cls = env->GetObjectClass(gEventHandle); //獲得類對象 if (!cls) { LOGE("EventHandler: failed to get class reference"); return; } jmethodID methodID = env->GetStaticMethodID(cls, "callbackStatic", "(ILjava/lang/String;)V"); //靜態方法或成員方法 if (methodID) { jstring content = env->NewStringUTF(description); env->CallVoidMethod(gEventHandle, methodID,eventId, content); env->ReleaseStringUTFChars(content,description); } else { LOGE("EventHandler: failed to get the callback method"); } if (isAttached) myVm->DetachCurrentThread(); }

線程中回調
把c/c++中所有線程的創建,由pthread_create函數替換為由Java層的創建線程的函數AndroidRuntime::createJavaThread。
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) { return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); } static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { //異常檢測和排除 if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); LOGE_EX(env); env->ExceptionClear(); } } static void receive_callback(unsigned char *buf, int len) //回調 { int i; JNIEnv* env = AndroidRuntime::getJNIEnv(); jcharArray array = env->NewCharArray(len); jchar *pArray ; if(array == NULL){ LOGE("receive_callback: NewCharArray error."); return; } pArray = (jchar*)calloc(len, sizeof(jchar)); if(pArray == NULL){ LOGE("receive_callback: calloc error."); return; } //copy buffer to jchar array for(i = 0; i < len; i++) { *(pArray + i) = *(buf + i); } //copy buffer to jcharArray env->SetCharArrayRegion(array,0,len,pArray); //invoke java callback method env->CallVoidMethod(mCallbacksObj, method_receive,array,len); //release resource env->DeleteLocalRef(array); free(pArray); pArray = NULL; checkAndClearExceptionFromCallback(env, __FUNCTION__); } public void Receive(char buffer[],int length){ //java層函數 String msg = new String(buffer); msg = "received from jni callback" + msg; Log.d("Test", msg); }

jclass cls = env->GetObjectClass(obj);//取得Java類實例 jmethodID callbackID = env->GetMethodID(cls , "callback" , "(Ljava/lang/String;)V") ;//或得該回調方法句柄 if(callbackID == NULL) { cout << "getMethodId is failed " << endl ; } jstring native_desc = env->NewStringUTF(" I am Native"); env->CallVoidMethod(obj , callbackID , native_desc); //回調該方法,并且


5、傳對象到JNI調用

jclass stu_cls = env->GetObjectClass(obj_stu); //或得Student類援用 if(stu_cls == NULL) { cout << "GetObjectClass failed " ; } //下面這些函數操作,我們都見過的。O(∩_∩)O~ jfieldID ageFieldID = env->GetFieldID(stucls,"age","I"); //取得得Student類的屬性id jfieldID nameFieldID = env->GetFieldID(stucls,"name","Ljava/lang/String;"); // 取得屬性ID jint age = env->GetIntField(objstu , ageFieldID); //取得屬性值 jstring name = (jstring)env->GetObjectField(objstu , nameFieldID);//取得屬性值 const char * c_name = env->GetStringUTFChars(name ,NULL);//轉換成 char * string str_name = c_name ; env->ReleaseStringUTFChars(name,c_name); //釋放援用 cout << " at Native age is :" << age << " # name is " << str_name << endl ;
6、與C++互轉

jbytearray轉c++byte數組

jbyte * arrayBody = env->GetByteArrayElements(data,0); jsize theArrayLengthJ = env->GetArrayLength(data); BYTE * starter = (BYTE *)arrayBody;


jbyteArray 轉 c++中的BYTE[] 
jbyte * olddata = (jbyte*)env->GetByteArrayElements(strIn, 0); jsize oldsize = env->GetArrayLength(strIn); BYTE* bytearr = (BYTE*)olddata; int len = (int)oldsize;


C++中的BYTE[]轉jbyteArray 
jbyte *by = (jbyte*)pData; jbyteArray jarray = env->NewByteArray(nOutSize); env->SetByteArrayRegin(jarray, 0, nOutSize, by);


jbyteArray 轉 char * 
char* data = (char*)env->GetByteArrayElements(strIn, 0);


char* 轉jstring
jstring WindowsTojstring(JNIEnv* env, char* str_tmp) { jstring rtn=0; int slen = (int)strlen(str_tmp); unsigned short* buffer=0; if(slen == 0) { rtn = env->NewStringUTF(str_tmp); } else { int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str_tmp, slen, NULL, 0); buffer = (unsigned short*)malloc(length*2+1); if(MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str_tmp, slen, (LPWSTR)buffer, length) > 0) { rtn = env->NewString((jchar*)buffer, length); } } if(buffer) { free(buffer); } return rtn; }


char* jstring互轉
JNIEXPORT jstring JNICALL Java_com_explorer_jni_SambaTreeNative_getDetailsBy (JNIEnv *env, jobject jobj, jstring pc_server, jstring server_user, jstring server_passwd) { const char *pc = env->GetStringUTFChars(pc_server, NULL); const char *user = env->GetStringUTFChars(server_user, NULL); const char *passwd = env->GetStringUTFChars(server_passwd, NULL); const char *details = smbtree::getPara(pc, user, passwd); jstring jDetails = env->NewStringUTF(details); return jDetails; }
4、Android.mk、Application.mk
1、Android.mk

Android.mk文件是GNU Makefile的1小部份,它用來對Android程序進行編譯,Android.mk中的變量都是全局的,解析進程會被定義。

1個Android.mk文件可以編譯多個模塊,模塊包括:APK程序、JAVA庫、CC++利用程序、CC++靜態庫、CC++同享庫。

簡單實例以下:

LOCAL_PATH := $(call my-dir) #表示是當前文件的路徑 include $(CLEAR_VARS) #指定讓GNU MAKEFILE該腳本為你清除許多 LOCAL_XXX 變量 LOCAL_MODULE:= helloworld #標識你在 Android.mk 文件中描寫的每一個模塊 MY_SOURCES := foo.c #自定義變量 ifneq ($(MY_CONFIG_BAR),) MY_SOURCES += bar.c endif LOCAL_SRC_FILES += $(MY_SOURCES) #包括將要編譯打包進模塊中的 C 或 C++源代碼文件 include $(BUILD_SHARED_LIBRARY) #根據LOCAL_XXX系列變量中的值,來編譯生成同享庫(動態鏈接庫)


GNU Make系統變量

變量 描寫
CLEAR_VARS指向1個編譯腳本,幾近所有未定義的 LOCAL_XXX 變量都在"Module-description"節中列出。必須在開始1個新模塊之前包括這個腳本:include$(CLEAR_VARS),用于重置除LOCAL_PATH變量外的,所有LOCAL_XXX系列變量。
BUILD_SHARED_LIBRARY指向編譯腳本,根據所有的在 LOCAL_XXX 變量把列出的源代碼文件編譯成1個同享庫。
BUILD_STATIC_LIBRARY1個 BUILD_SHARED_LIBRARY 變量用于編譯1個靜態庫。靜態庫不會復制到的APK包中,但是能夠用于編譯同享庫。
TARGET_ARCH目標 CPU平臺的名字,  和 android 開放源碼中指定的那樣。如果是arm,表示要生成 ARM 兼容的指令,與 CPU架構的修訂版無關。
TARGET_PLATFORMAndroid.mk 解析的時候,目標 Android 平臺的名字.詳情可參考/development/ndk/docs/stable- apis.txt.
TARGET_ARCH_ABI支持目標平臺
TARGET_ABI目標平臺和 ABI 的組合,它事實上被定義成$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)  ,在想要在真實的裝備中針對1個特別的目標系統進行測試時,會有用。在默許的情況下,它會是'android⑶-arm'。
  

模塊描寫變量

變量 描寫
LOCAL_PATH這個變量用于給出當前文件的路徑。必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir)  這個變量不會被$(CLEAR_VARS)清除,因此每
個 Android.mk 只需要定義1次(即便在1個文件中定義了幾個模塊的情況下)。
LOCAL_MODULE這是模塊的名字,它必須是唯1的,而且不能包括空格。必須在包括任1的$(BUILD_XXXX)腳本之前定義它。模塊的名字決定了生成文件的名字。例如,如果1個1個同享庫模塊的名字是,那末生成文件的名字就是 lib.so。但是,在的 NDK 生成文件中(或 Android.mk 或 Application.mk),應當只觸及(援用)有正常名字的其他模塊。
LOCAL_SRC_FILES這是要編譯的源代碼文件列表。只要列出要傳遞給編譯器的文件,由于編譯系統自動計算依賴。注意源代碼文件名稱都是相對 LOCAL_PATH的,你可使用路徑部份。
LOCAL_CPP_EXTENSION這是1個可選變量, 用來指定C++代碼文件的擴大名,默許是'.cpp',但是可以改變它。
LOCAL_C_INCLUDES可選變量,表示頭文件的搜索路徑。
LOCAL_CFLAGS可選的編譯器選項,在編譯 C 代碼文件的時候使用。
LOCAL_CXXFLAGS與 LOCAL_CFLAGS同理,針對 C++源文件。
LOCAL_CPPFLAGS與 LOCAL_CFLAGS同理,但是對 C 和 C++ source files都適用。
LOCAL_STATIC_LIBRARIES表示該模塊需要使用哪些靜態庫,以便在編譯時進行鏈接。
LOCAL_SHARED_LIBRARIES表示模塊在運行時要依賴的同享庫(動態庫),在鏈接時就需要,以便在生成文件時嵌入其相應的信息。注意:它不會附加列出的模塊到編譯圖,也就是依然需要在Application.mk 中把它們添加到程序要求的模塊中。
LOCAL_LDLIBS編譯模塊時要使用的附加的鏈接器選項。這對使用‘-l’前綴傳遞指定庫的名字是有用的。
LOCAL_ALLOW_UNDEFINED_SYMBOLS默許情況下, 在試圖編譯1個同享庫時,任何未定義的援用將致使1個“未定義的符號”毛病。
LOCAL_ARM_MODE默許情況下, arm目標2進制會以 thumb 的情勢生成(16 位),你可以通過設置這個變量為 arm如果你希望你的 module 是以 32 位指令的情勢。
LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH在 Android.mk 文件中, 還可以用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最后的目標安裝路徑.
不同的文件系統路徑用以下的宏進行選擇:
  TARGET_ROOT_OUT:表示根文件系統。
   TARGET_OUT:表示 system文件系統。
   TARGET_OUT_DATA:表示 data文件系統。
用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) 
至于LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH的區分,暫時還不清楚。

GNU Make 功能宏

變量 描寫
my-dir返回當前 Android.mk 所在的目錄的路徑,相對 NDK 編譯系統的頂層。
all-subdir-makefiles返回1個位于當前'my-dir'路徑的子目錄中的所有Android.mk的列表。
this-makefile返回當前Makefile 的路徑(即這個函數調用的地方)
parent-makefile返回調用樹中父 Makefile 路徑。即包括當前Makefile的Makefile 路徑。
grand-parent-makefile返回調用樹中父Makefile的父Makefile的路徑
  

范例:


2、

編譯1個簡單的APK

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage # Tell it to build an APK include $(BUILD_PACKAGE)

編譯1個依賴靜態.jar文件的APK 

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # List of static libraries to include in the package LOCAL_STATIC_JAVA_LIBRARIES := static-library # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage # Tell it to build an APK include $(BUILD_PACKAGE) 注:LOCAL_STATIC_JAVA_LIBRARIES 后面應是你的APK程序所需要的JAVA庫的JAR文件名。


編譯1個需要platform key簽名的APK

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := platform # Tell it to build an APK include $(BUILD_PACKAGE) 注:LOCAL_CERTIFICATE 后面應當是簽名文件的文件名

編譯1個需要特殊vendor key簽名的APK 

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := vendor/example/certs/app # Tell it to build an APK include $(BUILD_PACKAGE)

裝載1個普通的第3方APK

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Module name should match apk name to be installed. LOCAL_MODULE := LocalModuleName LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE := platform include $(BUILD_PREBUILT)

裝載需要.so(動態庫)的第3方apk

LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) LOCAL_MODULE := baiduinput_android_v1.1_1000e LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE := platform include $(BUILD_PREBUILT) ################################################################# ####### copy the library to /system/lib ######################### ################################################################# include $(CLEAR_VARS) LOCAL_MODULE := libinputcore.so LOCAL_MODULE_CLASS := SHARED_LIBRARIES LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) LOCAL_SRC_FILES := lib/$(LOCAL_MODULE) OVERRIDE_BUILD_MODULE_PATH := $(TARGET_OUT_INTERMEDIATE_LIBRARIES) include $(BUILD_PREBUILT)

編譯1個靜態java庫 

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Any libraries that this library depends on LOCAL_JAVA_LIBRARIES := android.test.runner # The name of the jar file to create LOCAL_MODULE := sample # Build a static jar file. include $(BUILD_STATIC_JAVA_LIBRARY) 注:LOCAL_JAVA_LIBRARIES表示生成的java庫的jar文件名。

編譯C/C++利用程序模板

LOCAL_
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产精品视频一区二区三区不卡 | 玖玖在线视频 | 国产三级国产精品国产国在线观看 | 日本一区二区视频 | 欧美日韩性视频一区二区三区 | 日韩欧美精品综合一区二区三区 | 最近最新视频中文字幕3 | 亚洲一二区视频 | 国产成人精品久久二区二区 | 一区二区三区免费看 | 日本中文字幕视频在线看 | 国产精品v欧美精品v日本精 | 黑人性猛交xxxx乱大交一 | 玖玖色资源网 | 欧美视频日韩专区午夜 | 亚洲成人福利在线观看 | 国产精品久久久久久久y | 一级空姐毛片 | 中文字幕色视频 | 美女网站在线观看视频免费的 | 欧美久久xxxxxx影院 | 精品福利一区二区免费视频 | 亚洲女人被黑人巨大进入 | 午夜影院在线观看视频 | 中文字幕资源在线 | 日韩日韩日韩日韩日韩 | 2021年中文字幕视频 | 成人亚洲国产精品久久 | 国产精品久久久久久吹潮 | 久久综合九色综合亚洲 | 欧美14一15sex性h | 国产乱码精品一区二区三区中 | 亚洲 自拍 欧美 综合 | 一级黄色欧美 | 亚洲精品乱码久久久久久蜜桃 | 色网色| 国产一区二区三区在线观看视频 | 欧美高清3dfreexxxx性 | 一级做性色a爰片久久毛片 一级做性色a爰片久久毛片免费 | 亚洲综合国产 | 亚洲欧美另类日韩 |