1. 程式人生 > >android原始碼平臺下JAR包的引入與編譯

android原始碼平臺下JAR包的引入與編譯

android原始碼平臺下JAR包的引入與編譯

2018年01月07日 12:26:45 very_on 閱讀數:775

轉自:http://blog.csdn.net/sjz_iron/article/details/8348265

 

在應用開發過程中,常常需要引入第三方JAR包,或將自己的一些程式碼打包為JAR包以供其他應用使用,以下將描述這些操作的過程。需要注意的是,本文所述方法皆是在原始碼平臺下的操作。

 

1.引入第三方JAR包

圖1 測試程式根目錄

        如圖1,在應用AppsAut中需要引入第三方JAR包:appsaut.jar,我們將其放到libs目錄中,Android.mk檔案應如下編寫:       

圖2 Android.mk的編寫

        圖中帶有紅色下劃線的第6行,第17行及第20行程式碼為引入第三方JAR包的核心程式碼,其含義如下。

        第6行:指定變數LOCAL_STATIC_JAVA_LIBRARIES的值,其值appsaut代表了所需引入的JAR包,appsaut只是一個別名,可任取,但必須要與第17中的保持一致;

        第17行:為LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES賦值。其中冒號前的appsaut要與第6行LOCAL_STATIC_JAVA_LIBRARIES的值相同,而冒號後則為此JAR 包的路徑:即應用根目錄libs目錄中的appsaut.jar檔案;

        第20行:呼叫BUILD_MULTI_PREBUILT命令對appsaut.jar進行預編譯。

        經過以上三步,即可將JAR包appsaut.jar編譯到最終的APK包中。在此需要說明的是,第三方appsaut.jar包為LOCAL_STATIC_JAVA_LIBRARIES,即.class檔案歸檔後得到的JAR包,而BUILD_MULTI_PREBUILT命令的作用則是將靜態JAVA類庫壓縮到.dex檔案中--這是在android系統中所使用的JAVA包。

        注意:如果系統中存在與第三方JAR包相同的包,則此時我們的操作會失敗。

 

2.編譯自己的JAR包之一(失敗)

        在平臺中編譯自己的JAR包,我們將原始碼目錄appsaut存放在/external中。其目錄結構如下:

 

圖3 appsaut目錄結構

        原始碼存放於src目錄,通過編寫Android.mk及appsaut.xml檔案引導JAR包的編譯,最終生成的JAR包不僅在平臺中可用,同時可匯入到手機系統/system/framework中,成為系統檔案以供其他程式呼叫。

[plain]view plaincopy

  1. LOCAL_PATH := $(call my-dir)  
  2. # the custom dex'ed emma library ready to put on a device.  
  3. # ============================================================  
  4. include $(CLEAR_VARS)  
  5. LOCAL_SRC_FILES := $(call all-java-files-under, src)  
  6. LOCAL_MODULE := appsaut  
  7. LOCAL_MODULE_TAGS := optional  
  8. include $(BUILD_JAVA_LIBRARY)  
  9.   
  10. #build the permission xml  
  11. #=============================================================  
  12. #MAKE_XML  
  13. include $(CLEAR_VARS)  
  14. LOCAL_MODULE := appsaut.xml  
  15. LOCAL_MODULE_TAGS := optional  
  16. LOCAL_MODULE_CLASS := ETC  
  17. LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions  
  18. LOCAL_SRC_FILES := $(LOCAL_MODULE)  
  19. include $(BUILD_PREBUILT)  

程式碼段1 appsaut模組的Android.mk檔案

以上程式碼為工程appsaut的Android.mk的內容。此段程式碼完成兩件事情:編譯JAR包與其對應的xml檔案。程式碼01~07為變數賦值,第8行的程式碼通過呼叫命令BUILD_JAVA_LIBRARY將appsaut目錄中的程式碼編譯為JAR包,此命令的執行會在out/target/common/obj/JAVA_LIBRARIES/下生成目錄appsaut_intermediates,此目錄下便存放著編譯生成的JAR和dex檔案;同時,系統還會將目錄JAR包複製到out/target/product/<product-name>/system/framework/路徑下,如此以來,最終燒寫到手機裡的系統中的system/framework中便會存在此JAR包。

        但是僅存在JAR包是不夠的,還需要與之對應的許可權檔案:即appsaut目錄下的appsaut.xml檔案,此檔案的內容如下所示:

[plain]view plaincopy

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <permissions>  
  3.     <library name="com.test.appsaut" file="/system/framework/appsaut.jar"/>  
  4. </permissions>  

程式碼段2 appsaut.jar所對應的許可權檔案appsaut.xml

此檔案中的標籤<library>聲明瞭一個JAR包,其中name指定了其名稱,而file則指定了其存放路徑。Android.mk檔案中的程式碼10~19通過對appsaut.xml的編譯,最終將其生成到out/target/product/<product-name>/system/etc/permissions/中,這樣執行在手機裡的程式能夠在此檔案的引導下使用我們編譯的JAR包:appsaut.jar。與此同時,應用端的Android.mk檔案中需要通過語句LOCAL_JAVA_LIBRARIES := appsaut.jar宣告所使用的JAR包;而AndroidManifest.xml中則要新增如下語句:

                                         <uses-library name="com.test.appsaut"><uses-library>

來宣告引用的JAR包。遺憾的是,儘管如此折騰了一番,結果卻測試失敗,將以上的JAR包,XML檔案及APP應用PUSH到機器上,執行APP,無法找到JAR包中的類。可能是我本人的原因吧,終歸是沒有解決,OK,無奈之下不得不另謀他法,於是便有了下文。

 

3.將自己的程式碼編入android.jar包

        將手機ROOT後,進入到system/framework目錄,可以看到存在framework.jar檔案,此JAR包即android框架層的核心API,我們可以將自己的程式碼編入此JAR包從而成為系統API,如此則可由上層APP任意呼叫我們的程式碼--事實上是擴充套件了系統的API。

        首先,將我們的程式碼存放到android原始碼的frameworks/base目錄下,需要注意的是,程式碼的目錄結構必須為mylib/java/android/mylib(假設我們的程式碼均由JAVA寫成);

        其次,修改build/core/pathmap.mk檔案,在變數FRAMEWORKS_BASE_SUBDIRS後新增我們的程式碼,如下圖所示:

圖4 將程式碼編入android.jar

        最後,編譯framework.jar(命令為:mmm frameworks/base),並將其替換掉手機中的system/framework/framework.jar,我們自己的程式碼便成為了系統API。

 

4.將自己的程式碼編入ext.jar

        3中的方法固然可行,但總覺得不妥--除非我們真的是在定製系統,否則將自己的程式碼放置到external目錄下編譯方為上策。在瀏覽frameworks/base/Android.mk時,無意中看到了如下內容:

圖5 編譯ext.jar的程式碼

顯然,在生成framework.jar的同時還將external下的部分程式碼編譯生成了另一個JAR包:ext.jar(LOCAL_MODULE := ext),於是迅速進入手機裡的system/framework目錄,果然看到一個ext.jar檔案,這就意味著我們可以將自己的程式碼放到external目錄中並編譯到ext.jar(從名字來看ext應該是extention的縮寫吧,呵呵)

        首先,將程式碼放入external目錄,此時的目錄結構可任意,如mylib/src/com/test/mylib;

        其次,在圖5所示程式碼中,將我們的程式碼路徑新增到變數ext_dirs中,如下圖所示:

圖6 將自己的程式碼編入到ext.jar中

        最後,重新編譯ext.jar(命令依然是mmm frameworks/base),並將得到的ext.jar替換掉手機中的system/framework/ext.jar。

        注意:在編譯應用程式時,如果此APP用到了ext.jar中的程式碼,需要在Android.mk檔案中引入此JAR包:LOCAL_JAVA_LIBRARIES := ext。

 

5.BUILD_JAVA_LIBRARY與BUILD_STATIC_JAVA_LIBRARY

        在Android.mk中可通過呼叫include $(BUILD_JAVA_LIBRARY)和include $(BUILD_STATIC_JAVA_LIBRARY)來分別生成目標裝置上的共享JAVA庫與靜態JAVA庫。二者的區別在於靜態JAVA庫是由.class檔案打包而成JAR包,它在任何一個JAVA虛擬機器上都可以執行;而共享JAVA庫則是在靜態庫的基礎上進一步打包成的.dex檔案,眾所周知,dex是在android系統上所使用的檔案格式。

        由以上結論可做出進一步的推論:即Android.mk中變數LOCAL_JAVA_LIBRARIES所指定的為android系統使用的dex類庫;而LOCAL_STATIC_JAVA_LIBRARIES變數所指定的則是.class檔案打包而成的JAR檔案:即靜態JAVA庫。

        BUILD_STATIC_JAVA_LIBRARY會生成out/target/common/obj/JAVA_LIBRARIES/appsaut_intermediates目錄及其下的JAR檔案;而BUILD_JAVA_LIBRARY生成此目錄的同時會將其中的JAR包複製到out/target/product/<product-name>/system/framework/中;除此之外,還存在BUILD_HOST_JAVA_LIBRARY命令則是在out/host/linux-x86/framework目錄下生成相應的JAR包。分別使用此三條命令執行的結果如下所示:注意其中帶有紅色下劃線的LOG資訊。

圖4 BUILD_STATIC_JAVA_LIBRARY的LOG資訊

圖5 BUILD_JAVA_LIBRARY的LOG資訊

圖6 BUILD_HOST_JAVA_LIBRARY的LOG資訊

6.平臺中新增預編譯的JAR檔案

        如果需要將已經存在的JAR檔案新增到整個編譯系統中,則相應的Android.mk檔案需要如下配置(假設新增的JAR包為com.test.myjar):

圖7 平臺中新增預編譯的JAR包

        注:

                (1)如程式碼所示,呼叫的命令為include $(BUILD_PREBUILT);

                (2)此jar包為LOCAL_JAVA_LIBRARIES,如程式碼所示:LOCAL_MODULE_CLASS := JAVA_LIBRARIES,即dex歸檔檔案。

                (3)如果是STATIC_JAVA_LIBRARY是否也能如此新增?沒進行相關驗證,不得而知。如有興趣,可自行驗證。