在应用开发过程中,常常需要引入第三方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中,成为系统文件以供其他程序调用。
LOCAL_PATH := $(call my-dir)
# the custom dex'ed emma library ready to put on a device.
# ============================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := appsaut
LOCAL_MODULE_TAGS := optional
include $(BUILD_JAVA_LIBRARY)
#build the permission xml
#=============================================================
#MAKE_XML
include $(CLEAR_VARS)
LOCAL_MODULE := appsaut.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
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/
但是仅存在JAR包是不够的,还需要与之对应的权限文件:即appsaut目录下的appsaut.xml文件,此文件的内容如下所示:
代码段2 appsaut.jar所对应的权限文件appsaut.xml
此文件中的标签
来声明引用的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/
图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是否也能如此添加?没进行相关验证,不得而知。如有兴趣,可自行验证。