有些类似的问题碰到过很多次,但大脑里总是各种碎片化的记忆,长时间记住这些碎片并不是人类大脑的强项,所以有事没事就要捋捋,知道前因后果才
能记忆深刻。
Android.mk
Android.mk 只是GNU Makefile的一小部分,用来编译module,这个module可以是app,也可以是library。Android.mk可能会被编译系统解析多次,所以
要谨慎定义变量,建议尽量不要在其中定义变量。
静态库与共享库的区别
简单来讲,静态库是在连接阶段直接拷贝到代码中使用的,而共享库是由加载器加载到内存,在运行时使用的。编译出来的静态库(这里指jar包)里每
个java文件对应的class文件都单独存在,可以直接导入Eclipse等IDE使用,而编译出来的共享库(jar包),内部是Android字节码Dex格式的文件,
一般无法导入Eclipse等IDE使用。Android.mk中由BUILD_JAVA_LIBRARY指定生成共享库,BUILD_STATIC_JAVA_LIBRARY指定生成静态库。
编译静态库和共享库
下面是两个生成静态库和动态库的例子。
生成静态库的mk文件:
LOCAL_PATH:= $(call my-dir )
include $(CLEAR_VARS)
LOCAL_MODULE := simple_game
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all -java -files -under , src)
LOCAL_SRC_FILES += $(call all -Iaidl -files -under , src)
include $(BUILD_STATIC_JAVA_LIBRARY)
生成共享库的mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := simple_game
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)
// 安装时需要一起安装的模块
LOCAL_REQUIRED_MODULES := simple_game.xml
// 设置生成共享库
include $(BUILD_JAVA_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := simple_game.xml
// 定制LOCAL_MODULE_PATH变量的值
LOCAL_MODULE_CLASS := ETC
// 设置安装的路径
LOCAL_MODULE_PATH := $(TARGET_OUT) /etc/permissions
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := simple_game.xml
// 将文件预置进系统
include $(BUILD_PREBUILT)
共享库需要一个xml文件配置安装的信息,LOCAL_REQUIRED_MODULES设置了该文件,当共享库安装时,LOCAL_REQUIRED_MODULES制定的模块也会安装到系
统中。
安装的位置由LOCAL_MODULE_PATH指定,当LOCAL_MODULE_PATH没有设置时,系统将会根据LOCAL_MODULE_CLASS的值来判断安装的位置,
LOCAL_MODULE_CLASS变量将通过/build/core/base_rules.mk文件设置默认的安装目录,常用的值有:
apk文件: APPS
so文件: SHARED_LIBRARIES
bin文件: EXECUTABLES
其他文件: ETC
当LOCAL_MODULE_PATH和LOCAL_MODULE_CLASS均没有设置时,系统会根据编译生成的不同模块(根据include$()判断)来自动设置LOCAL_MODULE_CLASS的值,
但遇到include $(BUILD_PREBUILT)编译选项时,系统不会设置模块的LOCAL_MODULE_CLASS,需要显示设置。
最后针对单一文件进行预编译需要设置BUILD_PREBUILT,对于多文件需要设置BUILD_MULTI_PREBUILT宏。
静态库和共享库的使用
完成了库的编译,接下来看看库的使用方法。
静态库很多情况来自第三方,包括jar包和第三方工程。首先,获得到jar后需要导入项目代码,一般放在libs目录下,接下来需要修改项目的mk,加入
编译静态库的代码,类似一下XML:
LOCAL_PATH:= $(call my-dir )
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := simple_game
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := simple_game:libs/simple_game. jar
include $(BUILD_MULTI_PREBUILT)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all -java -files -under , src)
LOCAL_SRC_FILES += $(call all -Iaidl -files -under , src)
LOCAL_PACKAGE_NAME := game
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
include $(BUILD_PACKAGE) 会结合LOCAL_PRIVILEGED_MODULE判断生成的apk是最终安装在/system/app下还是/system/priv-app下。
LOCAL_PROGUARD_ENABLED定义了编译apk时是否进行代码混淆,默认为full,将工程代码全部混淆,也可以用LOCAL_PROGUARD_FLAG_FILES配置混淆规则。
静态库的使用比较简单,下面来看看共享库的使用。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)
LOCAL_PACKAGE_NAME := game
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
// MODULE 依赖的共享库
LOCAL_JAVA_LIBRARIES += simple_game
// 安装时module时,共享库需要一起安装。
LOCAL_REQUIRED_MODULES := simple_game
include $(BUILD_PACKAGE)
上面是一个简单使用共享库的例子,LOCAL_JAVA_LIBRARIES定义了依赖的共享库,全编译时检查到该选项系统会先编译simple_game库,然后检查
LOCAL_REQUIRED_MODULES,决定是否安装该库(即是否在/system/framework下生成该库),注意,单编时mm, mm -B, mmm均不会编译module
使用的依赖文件,需要使用m+module(如: m game)来编译。
app在使用时千万别忘了在AndroidManifest.xml中添加该共享库:
<uses-library android:name ="simple_game" android:required ="false" />
有很多同学不注意就忘了,然后查了半天才恍然大悟,切记切记!
最后,类似$(call my-dir)宏函数的定义,可以在/build/core/definitions.mk中找到,其他变量定义可以在/build/core/base_rules.mk中找到。有
兴趣的同学可以去查看。