android源码平台下JAR包的引入与编译

时间:2024-04-09 11:12:46

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

在应用开发过程中,常常需要引入第三方JAR包,或将自己的一些代码打包为JAR包以供其他应用使用,以下将描述这些操作的过程。需要注意的是,本文所述方法皆是在源码平台下的操作。

 

1.引入第三方JAR包

android源码平台下JAR包的引入与编译

图1 测试程序根目录

        如图1,在应用AppsAut中需要引入第三方JAR包:appsaut.jar,我们将其放到libs目录中,Android.mk文件应如下编写:       

android源码平台下JAR包的引入与编译

图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中。其目录结构如下:

 

android源码平台下JAR包的引入与编译

图3 appsaut目录结构

        源码存放于src目录,通过编写Android.mk及appsaut.xml文件引导JAR包的编译,最终生成的JAR包不仅在平台中可用,同时可导入到手机系统/system/framework中,成为系统文件以供其他程序调用。

  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文件,此文件的内容如下所示:

  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后添加我们的代码,如下图所示:

android源码平台下JAR包的引入与编译

图4 将代码编入android.jar

        最后,编译framework.jar(命令为:mmm frameworks/base),并将其替换掉手机中的system/framework/framework.jar,我们自己的代码便成为了系统API。

 

4.将自己的代码编入ext.jar

        3中的方法固然可行,但总觉得不妥--除非我们真的是在定制系统,否则将自己的代码放置到external目录下编译方为上策。在浏览frameworks/base/Android.mk时,无意中看到了如下内容:

android源码平台下JAR包的引入与编译

图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中,如下图所示:

android源码平台下JAR包的引入与编译

图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信息。

android源码平台下JAR包的引入与编译

图4 BUILD_STATIC_JAVA_LIBRARY的LOG信息

android源码平台下JAR包的引入与编译

图5 BUILD_JAVA_LIBRARY的LOG信息

android源码平台下JAR包的引入与编译

图6 BUILD_HOST_JAVA_LIBRARY的LOG信息

6.平台中添加预编译的JAR文件

        如果需要将已经存在的JAR文件添加到整个编译系统中,则相应的Android.mk文件需要如下配置(假设添加的JAR包为com.test.myjar):

android源码平台下JAR包的引入与编译

图7 平台中添加预编译的JAR包

        注:

                (1)如代码所示,调用的命令为include $(BUILD_PREBUILT);

                (2)此jar包为LOCAL_JAVA_LIBRARIES,如代码所示:LOCAL_MODULE_CLASS := JAVA_LIBRARIES,即dex归档文件。

                (3)如果是STATIC_JAVA_LIBRARY是否也能如此添加?没进行相关验证,不得而知。如有兴趣,可自行验证。