【Android】java動態庫、靜態庫的編譯與使用

在Android的makefile編譯系統中,編譯結果是多種多樣的,這個可以從build/make/core/config.mk中看出,部分代碼如下所示:

BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_HEADER_LIBRARY:= $(BUILD_SYSTEM)/header_library.mk
BUILD_AUX_STATIC_LIBRARY:= $(BUILD_SYSTEM)/aux_static_library.mk
BUILD_AUX_EXECUTABLE:= $(BUILD_SYSTEM)/aux_executable.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk
BUILD_RRO_PACKAGE:= $(BUILD_SYSTEM)/build_rro_package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk
BUILD_NATIVE_BENCHMARK := $(BUILD_SYSTEM)/native_benchmark.mk
BUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mk
BUILD_FUZZ_TEST := $(BUILD_SYSTEM)/fuzz_test.mk
BUILD_HOST_FUZZ_TEST := $(BUILD_SYSTEM)/host_fuzz_test.mk

BUILD_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/shared_test_lib.mk
BUILD_HOST_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/host_shared_test_lib.mk
BUILD_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/static_test_lib.mk
BUILD_HOST_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/host_static_test_lib.mk

BUILD_NOTICE_FILE := $(BUILD_SYSTEM)/notice_files.mk
BUILD_HOST_DALVIK_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_java_library.mk
BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_static_java_library.mk

BUILD_HOST_TEST_CONFIG := $(BUILD_SYSTEM)/host_test_config.mk
BUILD_TARGET_TEST_CONFIG := $(BUILD_SYSTEM)/target_test_config.mk

在Android.mk中的用法如下所示:

include $(BUILD_XXX)

下面介紹Java相關的BUILD_JAVA_LIBRARYBUILD_STATIC_JAVA_LIBRARY

BUILD_STATIC_JAVA_LIBRARY

BUILD_STATIC_JAVA_LIBRARY表示編譯結果爲Java靜態庫,更準確地說就是一個與Android無關的純Java包。
以模塊名即LOCAL_MODULEabc爲例,使用aapt進行編譯。Android默認使用jack進行編譯,使用aapt進行編譯的方法是LOCAL_JACK_ENABLED := disabled
編譯完成後,編譯結果如下所示:

out/target/product/product_name/obj/JAVA_LIBRARIES/abc_intermediates
└── javalib.jar
out/target/common/obj/JAVA_LIBRARIES/abc_intermediates
├── anno 空目錄,應該是annotation相關的。
├── classes 裏面是所有的class文件。
├── classes-full-debug.jar
├── classes.jar
└── link_type 內容爲java:platform

product目錄下只有一個javalib.jar,這個是從common目錄下直接拷貝過來的,只是改了個名字而已。
javalib.jar是一個Java包,可以用解壓縮工具打開,也可以從命令行用jar命令解壓縮或直接查看裏面的文件。解壓縮命令jar -xvf javalib.jar,直接查看命令jar -tvf javalib.jar。其中有兩類文件,一類是純文本文件manifest,另一類是class爲後綴的編譯過的Java類數據文件。class文件中的部分內容可以從命令行用Java反編譯工具javap進行查看,javap xxx.class
common目錄下的兩個jar包是一樣的,同product目錄下的javalib.jar

BUILD_JAVA_LIBRARY

BUILD_JAVA_LIBRARY表示編譯結果爲Java動態庫,更準確地說是應用於Android的Java包。
編譯完成後,編譯結果如下所示:

out/target/product/product_name/obj/JAVA_LIBRARIES/abc_intermediates
└── javalib.jar
out/target/product/product_name/system/framework/abc.jar
out/target/common/obj/JAVA_LIBRARIES/abc_intermediates
├── anno 空目錄,應該是annotation相關的。
├── classes 裏面是所有的class文件。
├── classes-desugar.jar desugar即脫糖,爲了兼容性,如將Java8的lambda表達式轉換爲普通表達式。
├── classes.dex
├── classes-full-debug.jar 非脫糖的原始class。
├── classes.jar 同desugar。
├── desugar_dumped_classes 空目錄,desugar相關。
├── javalib.jar
├── link_type 內容爲java:platform
└── with-local 空目錄,local相關。

product目錄下的javalib.jar和abc.jar是相同的,裏面有兩個文件,manifest和classes.dex。可以看出,Java動態庫中的class文件變成了靜態庫中的dex文件,dex文件是Android Dalvik特有的文件格式。

上面介紹了Java庫的兩個不同的編譯結果,下面介紹使用方式。
Java庫有兩種使用方式,LOCAL_JAVA_LIBRARIESLOCAL_STATIC_JAVA_LIBRARIES

LOCAL_STATIC_JAVA_LIBRARIES

LOCAL_STATIC_JAVA_LIBRARIES表示把引用的外部Java庫(可以是上面提到的兩種形式的Java庫)直接編譯打包到本模塊中,在runtime時可以直接從本模塊中找到相關的東西。

LOCAL_JAVA_LIBRARIES

LOCAL_JAVA_LIBRARIES表示引用的外部Java庫(可以是上面提到的兩種形式的Java庫)在編譯時可以找到相關的東西,但並不打包到本模塊,在runtime時需要從別的地方查找,這個別的地方就是在編譯時將引用的外部Java庫的模塊名添加到PRODUCT_BOOT_JARS,例如Android原生的framework.jar就添了,PRODUCT_BOOT_JARS+=framework,否則在runtime時ClassLoader找不到需要的class。

綜上,Android中所謂的Java動態庫、靜態庫不同於C、C++的動態庫、靜態庫,編譯爲靜態庫時表示編譯爲原生的Java class壓縮包,編譯爲動態庫時表示編譯爲用於Android Dalvik的dex壓縮包,靜態引用時把外部庫直接打包過來,動態引用時需要將外部庫加到PRODUCT_BOOT_JARS

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章