http://blog.csdn.net/sgmenghuo/article/details/52238933
0、前言
作为android开发人员,经常面对这样的问题:网上下载的apk预制到系统,第三方oem提供编译好的库或者jar包等,你要将这些编制到你的系统中该如何做,那么这就不得不要去熟悉android编译环境,即一系列以LOCAL_XXX这样的变量。其实我们实际上碰到的编译MODULE就那么几样,下面我一一列出,可能不全面但是够用了。
1、第三方jar静态编译
源码环境使用第三方jar,需要关注三个LOCAL_XXX:
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES值格式为 别名:库相对路径
LOCAL_STATIC_JAVA_LIBRARIES
BUILD_MULTI_PREBUILT第三方包,编译类型为BUILD_MULTI_PREBUILT
其中zxing-1.6-core.jar放在apk源码目录的libs目录下
Android.mk如下:
- LOCAL_PATH :=$(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- #LOCAL_JAVA_LIBRARIES := ScannerAPI telephony-common telephony-msim
- LOCAL_STATIC_JAVA_LIBRARIES :=zxing android-support-v4 android-support-v13
- LOCAL_SRC_FILES :=$(call all-java-files-under, src)
- LOCAL_PACKAGE_NAME := SetInput2
- LOCAL_CERTIFICATE := platform #签名为platform
- include $(BUILD_PACKAGE)
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=zxing:libs/zxing-1.6-core.jar
- include $(BUILD_MULTI_PREBUILT)
2、可执行程序bin
比如我们想内置某些已编译好的busybox工具
Android.mk如下:
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := busybox
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := EXECUTABLES
- LOCAL_SRC_FILES := busybox
- LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/xbin
- include $(BUILD_PREBUILT)
3、不带so的apk
我在源码环境内置apk时发现有的可以运行,有的不能运行(说缺少lib64下的库),所以我分开说明如何内置这2中apk。
RAR工具解压apk没有lib文件夹的就是不带so的apk,最简单。
Android.mk如下:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := rsota
- LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
- LOCAL_MODULE_CLASS := APPS
- LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/app
- LOCAL_CERTIFICATE := platform
- LOCAL_MODULE_SUFFIX := .apk
- include $(BUILD_PREBUILT)
4、带so的apk
解压apk,发现lib文件夹含有xxx.so就是带so的apk,一般这些so默认是32位的,当前我们使用的大量的设备都是64位cpu,apk一运行就曝出找不到lib64类型的库,我们只需要让他调用apk解压的那些32位的so库就行了。
4.1、so库架构类型
这里穿插下关于lib下so的一些故事。如下是youku.apk中lib目录下的:
从这个图可以看出,这个youku.apk支持3种类型的cpu架构:arm,mips,x86,如果这里只有armeabi,那么是绝对不能正常安装到x86的android设备上的(比如使用x86架构的联想K900,好像还是科比代言,卖的好惨,反正我没看到有人用)。如果要提高多架构兼容,就得放入多架构的库,坏处就是apk好大啊吃手机内存啊,所以X86架构的手机好不好卖不是google决定的啊,是apk广大开发者决定的啊,没软件用,谁屌你,所以X86架构一般只能在几百块的水平打酱油,Windows
Phone也是没软件用的例子。话说到这跑题了,我们继续库的类型。lib目录下一般包含着几种类型:armeabi,armeabi-v7a,arm64-v8a,mips,x86。不过我们只关注arm的。
armeabi是普通老的32位arm,armeabi-v7a是带浮点运算及一些高级指令的32位arm,arm64-v8a是近几年A53 A57架构的64位arm,具体渊源见如下文章
《armeabi-v7a
armeabi arm64-v8a》 http://blog.csdn.net/mao520741111/article/details/50328669
现在市面上的基本都是32位apk,所以你基本看不到arm64-v8a库,但是从android L版本后确实是64位虚拟机了,当然是兼容32位的啦,在64位虚拟机运行当然会默认去运行lib64类型的库,而我们内置带so(内置一般都是32位的so)的apk就是要强制让apk去用现有的32位so,方法如下:
4.2、带so库apk例子
1)解包拿出lib下的armeabi或者armeabi-v7a下的xxx.so(最终内置到系统相对于apk目录的lib/arm下)
2)Android.mk既要内置apk还要copy库
注意预置模块,用到BUILD_PREBUILT
例子一
(apk,so和Android.mk在一个目录下):
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional eng
- LOCAL_MODULE := LiangdusIME
- LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
- LOCAL_MODULE_CLASS := APPS
- LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
- LOCAL_CERTIFICATE := platform
- LOCAL_MODULE_SUFFIX := .apk
- include $(BUILD_PREBUILT)
- include $(CLEAR_VARS)
- LOCAL_MODULE := libLDWWIme
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- LOCAL_MODULE_SUFFIX := .so
- LOCAL_MULTILIB := 32
- LOCAL_MODULE_TAGS := optional
- LOCAL_SRC_FILES := libLDWWIme.so
- LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app/LiangdusIME/lib/arm
- include $(BUILD_PREBUILT)
例子一有点缺点,要在$(product).mk中进行如下添加PRODUCT_PACKAGES += LiangdusIME libLDWWIme,在库比较少的时候没问题,多的时候,就比较麻烦了。比如一个apk有10个库,那么Android.mk都要要写10个module,$(product).mk也要写上这10个module名,麻烦死了,按道理就是一个apk,就写一个LOCAL_MODULE,其他的库应该有某种简单办法依赖一起内置,是的确实有那就是BUILD_MULTI_PREBUILT.
例子二
目录结构为
---Android.mk
---SeuicService.apk
---armeabi-v7a
|---libctp_jni.so
|---libkeypad_jni.so
---arm64-v8a
|---libctp_jni.so
|---libkeypad_jni.so
---SeuicService.apk
---armeabi-v7a
|---libctp_jni.so
|---libkeypad_jni.so
---arm64-v8a
|---libctp_jni.so
|---libkeypad_jni.so
- <span style="font-size:14px;">LOCAL_PATH := $(call my-dir)
- #====== so lab =====
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_LIBS := armeabi-v7a/libctp_jni.so
- LOCAL_MULTILIB := 32
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_MULTI_PREBUILT)
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_LIBS := armeabi-v7a/libkeypad_jni.so
- LOCAL_MULTILIB := 32
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_MULTI_PREBUILT)
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_LIBS := arm64-v8a/libctp_jni.so
- LOCAL_MULTILIB := 64
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_MULTI_PREBUILT)
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_LIBS := arm64-v8a/libkeypad_jni.so
- LOCAL_MULTILIB := 64
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_MULTI_PREBUILT)
- # ==== app ========================
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := SeuicService
- LOCAL_MODULE_CLASS := APPS
- LOCAL_CERTIFICATE := PRESIGNED #预签名过了,不需在签名了
- LOCAL_MODULE_PATH := $(TARGET_OUT)/app
- LOCAL_REQUIRED_MODULES := #本模块加入系统,我需要的依赖模块也必须加入
- libkeypad_jni
- libctp_jni
- LOCAL_SRC_FILES := SeuicService.apk
- include $(BUILD_PREBUILT)</span>
其中LOCAL_REQUIRED_MODULES表示预置SeuicService这个模块时,会先去执行依赖的模块,就是内置so库。这样执行的结果是SeuicService.apk放到了android系统的system/app下,armeabi-v7a的2个so库内置到了android系统的system/lib/下,arm64-v8a的2个so放到了system/lib64/下,apk不管运行在32还是64位虚拟机都能正常。
例子二的区别是so库谁都能用,例子一的so库只有自己能用。
例子三
目录结构为
---Android.mk
---Chrome.apk
---lib
|---armeabi-v7a
|---crazy.libchrome.so
|---libchrome.1847.114.so
|---crazy.libchrome.align
|---libchrome.1916.122.so
|---libchrome.1916.138.so
|---libchrome.1916.141.so
|---libchrome.1985.122.so
|---libchrome.1985.128.so
|---libchrome.1985.131.so
|---libchrome.1985.135.so
|---libchrome.2062.117.so
|---libchrome.2125.102.so
|---libchrome.2125.114.so
|---libchrome.2171.37.so
|---libchrome.2171.59.so
|---libchromium_android_linker.so
|---libchromeview.so
---Chrome.apk
---lib
|---armeabi-v7a
|---crazy.libchrome.so
|---libchrome.1847.114.so
|---crazy.libchrome.align
|---libchrome.1916.122.so
|---libchrome.1916.138.so
|---libchrome.1916.141.so
|---libchrome.1985.122.so
|---libchrome.1985.128.so
|---libchrome.1985.131.so
|---libchrome.1985.135.so
|---libchrome.2062.117.so
|---libchrome.2125.102.so
|---libchrome.2125.114.so
|---libchrome.2171.37.so
|---libchrome.2171.59.so
|---libchromium_android_linker.so
|---libchromeview.so
- LOCAL_PATH := $(call my-dir)
- # ==== app ========================
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := Chrome
- LOCAL_MODULE_CLASS := APPS
- LOCAL_CERTIFICATE := PRESIGNED
- LOCAL_MODULE_PATH := $(TARGET_OUT)/app
- LOCAL_POST_PROCESS_COMMAND := $(shell mkdir -p $(LOCAL_MODULE_PATH)/Chrome/lib/arm)
- LOCAL_POST_PROCESS_COMMAND := $(shell cp -r $(LOCAL_PATH)/lib/armeabi-v7a/* $(LOCAL_MODULE_PATH)/Chrome/lib/arm)
- LOCAL_SRC_FILES := Chrome.apk
- include $(BUILD_PREBUILT)
这是自由度最大的的方法,这个LOCAL_POST_PROCESS_COMMAND太厉害了简直为所欲为,因为它所引起的shell命令在make初期搜索Android.mk就执行了(我试过了可以多次加入执行)那个时候连system目录等都还没建立呢,这就是为什么我先mkdir再去cp,不然cp在目录没生成的情况下是失败的,而且注意了不报错。所以这种使用方式,需要你预先知道你要干什么,你得能预料结果,一般我就用mmm编译然后到out目录去验证。
5、源码集成带第三方so,jar的apk
这个是网上找到了
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_STATIC_JAVA_LIBRARIES := libbaidumapapi
- LOCAL_SRC_FILES := $(call all-subdir-java-files)
- LOCAL_PACKAGE_NAME := MyMaps
- include $(BUILD_PACKAGE)
- ##################################################
- include $(CLEAR_VARS)
- LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=libbaidumapapi:libs/baidumapapi.jar
- LOCAL_PREBUILT_LIBS :=libBMapApiEngine_v1_3_1:libs/armeabi/libBMapApiEngine_v1_3_1.so
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_MULTI_PREBUILT)
6、其他预编译
其他如各种配置文件的拷贝基本都是通过include $(BUILD_PREBUILT)或者include $(BUILD_MULTI_PREBUILT)来完成,比如
include $(CLEAR_VARS)
LOCAL_MODULE := com.seuic.misc.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
LOCAL_MODULE := com.seuic.misc.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
基本就是修改LOCAL_MODULE名字,或者修改LOCAL_MODULE_CLASS(类型检查,临时文件存放等),以及修改LOCAL_MODULE_PATH放到哪。
其中LOCAL_MODULE_CLASS值有:APP,ETC,STATIC_LIBRARIES,EXECUTABLES,JAVA_LIBRARIES,SHARED_LIBRARIES等
另外,Android.mk它也是makefile,不要以为它就是特殊的文件,什么都强制照搬,思维会定在如何去用LOCAL_XXX上面,如果你足够熟悉,你可以更灵活点,当然可能不好看。
顺便提下
1)上面看到LOCAL_MODULE_TAGS := optional都是要在$(PRODUCT).mk中将模块名加入到PRODUCT_PACKAGES中的,否则make不编译别找我。
2)将so提升为系统库,就是对应so放到android系统的system/lib或者system/lib64下,这样系统中任何java文件就有机会通过System.loadLibrary("yyy"); 加载libyyy.so,但是,但但是,这个so不是普通c用的so,是jni格式的so。
3)将jar提升为系统包,就是将jar放到android系统的system/framework下,且添加权限,添加权限有2中方法(假设jar文件名为scanner.jar其java包名为com.seuic.scanner,模块名为scan)。
方法一:在$(PRODUCT).mk中添加PRODUCT_BOOT_JARS+=scan
方法二:在对应的*.rc中追加scanner.jar,用冒号分割,export BOOTCLASSPATH /system/framework/core.jar:scanner.jar,这个基本被方法一替代,不要再使用了,编译会自动展开PRODUCT_BOOT_JARS,在系统的root目录下生成init.environ.rc(内容全是export导出的环境变量)
方法三:这个方法独立性比较好,建议用这个方法。
- <?xml version="1.0" encoding="UTF-8"?>
- <permissions>
- <library
- name="com.seuic.scanner"
- file="/system/framework/scanner.jar"
- />
- </permissions>
http://zwz94.blog.163.com/blog/static/3206039520131111101412959/
这篇文章问的还是有点意义的,看看能加深理解