Android 系统内置APK

1.在 packages/apps 下面以需要预置的 APK的 名字创建一个新文件夹,以KeyTest为例:

2.将KeyTest.apk放入packages/apps/KeyTest下

3.创建Android.mk

  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Module name should match apk name to be installed
  4. LOCAL_MODULE := KeyTest
  5. LOCAL_MODULE_TAGS := optional
  6. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  7. LOCAL_MODULE_CLASS := APPS
  8. LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
  9. LOCAL_PRIVILEGED_MODULE := true
  10. LOCAL_CERTIFICATE := PRESIGNED
  11. #LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
  12. LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app
  13. include $(BUILD_PREBUILT)

复制代码


4.打开文件 device/mediatek/common/device.mk

将 KeyTest 添加到 PRODUCT_PACKAGES 里面

PRODUCT_PACKAGES += KeyTest

最后build工程

LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app 可以卸载,恢复出厂设置时恢复

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) 可以卸载,恢复出厂设置时不可恢复

LOCAL_PRIVILEGED_MODULE := true 以声明app放在/system/priv-app 不可卸载

默认是放在 /system/app 不可卸载

1. Android.mk 是什么?
      Android.mk 文件用来告知 NDK Build 系统关于Source的信息。Android.mk是GNU Makefile 的一部分,并且将Build System解析一次或者多次。但是尽量少的在Android.mk中声明变量,也不要假定任何东西不会在解析过程中定义。            
      Android.mk文件语法允许我们将Source打包成一个‘modules’,‘modules’可以是:动态库,静态库。只有动态库可以被 install/copy到应用程序包(APK),静态库则可以被链接入动态库。可以在一个Android.mk中定义一个或多个modules;也可以将同一份source 加进多个modules。
     Build System帮我们处理了很多细节而不需要我们再关心。例如:你不需要在Android.mk中列出头文件和外部依赖文件。NDK Build System自动帮我们提供这些信息。这也意味着,当用户升级NDK后,你将可以受益于新的toolchain/platform而不必再去修改Android.mk.

2. Android.mk 的语法

  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS)
  3. # Module name should match apk name to be installed
  4. LOCAL_MODULE := XXXXXX
  5. LOCAL_MODULE_TAGS := optional
  6. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  7. LOCAL_MODULE_CLASS := APPS
  8. LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
  9. LOCAL_PRIVILEGED_MODULE := true
  10. LOCAL_CERTIFICATE := PRESIGNED
  11. LOCAL_PREBUILT_JNI_LIBS := \
  12.     @lib/armeabi/libbutterfly.so \
  13.     @lib/armeabi/libluajava.so \
  14.     @lib/armeabi/libNinepatch.so \
  15.     @lib/armeabi/libSogouAgc_v1.so \
  16.     @lib/armeabi/libsogouupdcore.so \
  17.     @lib/armeabi/libweibosdkcore.so
  18. LOCAL_MULTILIB := 32
  19. include $(BUILD_PREBUILT)
复制代码


语法讲解:

LOCAL_PATH:= $(call my-dir)
每个Android.mk文件必须定义LOCAL_PATH为开始,它用于在开发tree中查找源文件,宏my-dir则由build System提供。返回包含Android.mk的目录路径。

include $(CLEAR_VARS)
CLEAR_VARS 变量由Build  System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_XXX. 例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但是不清理LOCAL_PATH。这个清理动作是必须的,因为所以的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。

LOCAL_MODULE := XXXXXX
LOCAL_MODULE 必须定义,以表示Android.mk中的每一个模块,名字必须唯一,不能包含空格。

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS  是指定在什么版下才会编译这个Android.mk
user: 指该模块只在user版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译

LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码,这里将模块打包为apk包

LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_CLASS 标识了所编译模块最后放置的位置,如果不指定,不会放到系统中,之后放在最后的obj目录下的对应目录中。

LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
指定当前模块的后缀。一旦指定,系统在产生目标文件时,会以模块名加后缀来创建目标文件

LOCAL_PRIVILEGED_MODULE := true
LOCAL_PRIVILEGED_MODULE 是Android ROM编译时的一个变量,其与编译、安装、权限管理等几个方面都有关系。对于Android系统应用,LOCAL_PRIVILEGED_MODULE 决定了其编译后的在ROM中的安装位置: 如果不设置或者设为false,安装位置为system/app; 如果设置为true,安装位置为system/priv-app。

LOCAL_CERTIFICATE := PRESIGNED
LOCAL_CERTIFICATE指apk的签名,可以有:
media    使用media签名文件签名
platform 使用平台签名文件签名
shared   使用shared签名文件签名
PRESIGNED 如果文件已经签过名,不需要重新签名,则使用PRESIGNED。

LOCAL_PREBUILT_JNI_LIBS := \ XXXX  、LOCAL_MULTILIB :=32  
因为Android5.1 是64位编译环境,因此需要将32位的so库提取出来,使用的32位的lib库,提取出来的lib库,放在/system/priv-app/app文件名/下

include $(BUILD_PREBUILT)
BUILD_PREBUILT               :该模块已经预先编译
它负责收集自从上次调用 include $(CLEAR_VARS)  后的所有LOCAL_XXX信息。并决定编译为什么。
BUILD_STATIC_LIBRARY     :编译为静态库。 
BUILD_SHARED_LIBRARY    :编译为动态库 
BUILD_EXECUTABLE           :编译为Native C可执行程序  
BUILD_SHARED_LIBRARY    :是Build System提供的一个变量,指向一个GNU Makefile Script。
NDK还定义了很多其他的BUILD_XXX_XXX变量,它们用来指定模块的生成方式。

关于多个内置apk的问题

目前5.0之后项目预置方式通用步骤为:

  • 建立apk文件夹;
  • 置目标apk到该文件夹下;
  • 解压缩apk查看是否包含lib/文件夹(apk项目是否包含lib库文件);
  • 在该文件夹下编写Android.mk脚本 ;

Android系统mk文件中打印输出 

makefile中输出信息的方法有:$(warning xxx) 或 $(error xxx)

$(warning  " LOCAL_LDLIBS =  $(LOCAL_LDLIBS)")

对于apk预置路径,在Android.mk中可以通过以下方式指名:

a) 默认预置apk到system/app/目录(普通系统apk,不可卸载),如前文Android.mk脚本编写之后即可;
b) 预置apk到system/priv-app/目录(系统核心apk,不可卸载),在前文Android.mk脚本中添加并配置变量:

 LOCAL_PRIVILEGED_MODULE := true

c) 预置apk到data/app/目录并且卸载后不需要再会恢复,在前文Android.mk脚本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)

预置apk到data/app/目录并且卸载后恢复出厂可以恢复,在前文Android.mk简本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app

对于包含lib库文件的apk,还需要根据预置目标路径,在mk脚本中作不同的处理:

方法一 不从apk中解压lib库而直接添加

如下例,在Android.mk中添加并配置变量(注意路径对应):

LOCAL_PREBUILT_JNI_LIBS = \
@lib/armeabi-v7a/libcryptox.so \
@lib/armeabi-v7a/libfb.so 

注意前面的 @符号,@标识符会将apk中的so抽离出来,拷贝到对应编译后的apk目录;

方法二 手动解压lib文件到当前apk的编译目录并添加

先解压当前apk内的lib文件夹到当前apk编译目录,同方法一在Android.mk中添加并配置变量(注意路径对应),如下例:

LOCAL_PREBUILT_JNI_LIBS = \
lib/armeabi-v7a/libcryptox.so \
lib/armeabi-v7a/libfb.so 

若当前apk包含的lib库文件数量比较多时,上述代码可以通过修改为如下代码进行优化,优化的思路是用递归搜索来替代手工对lib库文件进行添加:

###清空临时变量JNI_LIBS 
JNI_LIBS :=
###当前目录递归搜索
$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))
###获取搜索文件目录集(相对目录)
LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))

然后需要注意当前Android环境是否符合apk运行条件(64位和32位)并配置apk运行环境

之所以要配置apk运行环境,是因为包含lib库的apk在添加lib库到编译环境之后,在Android环境和apk运行条件不符的情况下,需要在编译环境中指定环境。举例说明:

目前一般的apk运行环境为32位Android系统环境,当在64位Android系统中预置带有lib库的apk时,手动添加lib库文件到编译环境后,默认情况下编译环境会在编译后apk目录建立64位的环境的lib库路径 /lib/arm64,虽然编译过程未报错,但之后在执行该apk时,会出现apk因找不到lib库而报错

因此,需要在Android.mk中对当前apk编译环境进行配置,配置的方法常见的也有两种:

<1>指定编译目标为 32位 或 64位

在Android目标中添加并配置变量:
 

LOCAL_MULTILIB := 
###可选值 /32/64/first/both 

不同的值含义如下:

“both”: build both 32-bit and 64-bit.
“32”: build only 32-bit.> * “64”: build only 64-bit.
“first”: build for only the first arch (32-bit in 32-bit devices and 64-bit in 64-bit devices).
“”: the default; the build system decides what arch to build based on the module class and other LOCAL_ variables, such as LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY, etc.

此处,default值会根据当前已有的其他相关值方式来进行编译

如下是一个完整的Android.mk脚本示例,其中apk运行环境为32位,系统为64位:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := UCBrowser
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := HK_UCBrowser*.apk
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MULTILIB := 32
JNI_LIBS :=
$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))
LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))
include $(BUILD_PREBUILT)

最后编写管理脚本集中管理预置apk
预置三方apk一般根据客户项目的不同而有所差异,因此如前文所述,可以将需要预置的apk文件夹放到一个总文件夹内,该文件夹可以采用与客户项目有关的命名用以区分不同客户项目预置,并在该文件夹根目录另外写一个Android.mk (管理脚本), 这样便可以根据客户项目对预置apk进行管理。以下是据此更新后的预置目录,具体可以根据原理自行调整:
Customer1/
-/Android.mk 管理脚本
-/Test1
—-/Android.mk 编译脚本
—-/Test1.apk
—-/lib/*
-/Test2
—-/Android.mk 编译脚本
—-/Test2.apk
—-/lib/*
Customer2/
-/Android.mk 管理脚本
-/Test3
—-/Android.mk 编译脚本
—-/Test1.apk
—-/lib/*
-/Test4
—-/Android.mk 编译脚本
—-/Test2.apk
—-/lib/*

对于 管理脚本 的编写,如下例:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
###此处也可以在此添加一个宏变量来控制是否执行以下代码
###if($(strip $(XXX_CUSTOMER1_APP)),yes))
SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)
$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk)))
PRODUCT_PACKAGES += \
Test1\
Test2
###endif

其中 $(shell find $(LOCAL_PATH)/apps/ -name Android.mk) 返回一个遍历搜索子目录 Android.mk 的路径集合,此处也可以采用手动添加指定路径的方式来控制具体预置的apk是否编译 :

###替换
###SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)
###$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk)))
###为
include Customer1/Test1/Android.mk
include Customer1/Test2/Android.mk

同时,PRODUCT_PACKAGES 变量指定将哪些编译完成的apk 打包到项目最终编译生成的Android系统镜像文件中,如上代码中,其值恰恰就是预置apk的编译脚本中定义的 LOCAL_MODULE (即编译后该apk的名称)的值。

你可能感兴趣的:(mtk,android,android,studio,ide)