安卓系统预置应用apk的几种方式 - 曾经年少666

时间:2024-03-11 15:17:54

安卓系统预置应用apk的几种方式

工作背景:根据客户的需求需要在系统中集成一些apk,并且对集成的要求不同,有些需要集成后不能卸载,有些需要集成后可以卸载。要求不同,实现的方法也不同。目前遇到的几种需求如下:

A)在安卓系统中预置可以卸载的应用apk,手动可以卸载,恢复出厂设置时,系统会重新安装这些应用apk

实现方法:

1、在device/XXXX/x6818下面建立preinstall文件夹,在该文件夹内创建init.preload.sh文件:

#!/system/bin/sh
# ln preload apks
if [ ! -f "/data/app/exist" ]; then
echo "preloading application ..." 
for FILE in `ls /system/preload`;do
ln -s /system/preload/$FILE/$FILE.apk /data/app/preload_$FILE.apk
done
sync
echo "completed!" > /data/app/exist
chmod 777 /data/app/exist
sync
fi

(1、首先会判断标识(即/data/app/exist这个节点)是否存在,如果存在则不执行链接命令,如果不存在,则执行Linux命令link,把预装应用安装包链接到data/app下。注:在终端设备第一次开机前不在data分区设置标识。

2、在data分区添加标识。
3、扫描data分区的链接文件,根据链接文件实际扫描到预装应用安装包。开机过程中,Package Manager Service会分别扫描system分区和data 分区的应用程序目录,根据应用程序所在分区为其设置相应属性。扫描完后,根据应用程序的相应属性将其安装到终端设备。
4、终端设备非第一次开机时,直接获取终端设备第一次开机时建立的链接文件。开机时,仍会执行init.preload.sh脚本,由于已添加标识,因此当判断出存在标识时,则不执行链接命令。
5、恢复出厂设置会删除data分区的数据,也就是链接文件和标识都将被删除。)

2、在preinstall文件夹内创建Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE       := init.preload.sh
LOCAL_MODULE_TAGS  := optional eng
LOCAL_MODULE_CLASS := ETC
LOCAL_SRC_FILES    := init.preload.sh
include $(BUILD_PREBUILT)
include $(LOCAL_PATH)/preload/preload.mk

3、在preinstall文件夹内创建preload文件夹,在该文件夹下创建preload.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE            := meiweibudengdai
LOCAL_SRC_FILES         := meiweibudengdai/meiweibudengdai.apk
LOCAL_MODULE_CLASS      := APPS
LOCAL_MODULE_TAGS       := optional
LOCAL_CERTIFICATE       := PRESIGNED
LOCAL_DEX_PREOPT        := false
LOCAL_MODULE_SUFFIX     := .apk
LOCAL_MODULE_PATH       := $(TARGET_OUT)/preload
include $(BUILD_PREBUILT)

注:LOCAL_CERTIFICATE:= PRESIGNED指用软件自带的签名。对应的LOCAL_CERTIFICATE:= platforms 是指用android源码中的platform对其进行签名

LOCAL_CERTIFICATE指签名方式,如果是platform,代表签名成系统软件, 如果还是PRESIGND,表示用的是apk原本的签名。

4、在preload文件夹内创建应用程序文件夹***,将应用程序***.apk放在应用程序文件夹***内

5、修改device/XXXX/init.x6818.rc文件,定义在init.x6818.rc中的服务preload-sh,其作用是执行init.preload.sh脚本。代码如下:

service preload-sh /system/bin/sh /system/etc/init.preload.sh
     class main
     user root
     oneshot

(此文件格式由安卓初始化语言定义,service为关键字用来声明一个Service:

 preload-sh代表Service的名字,
 /system/bin/sh代表所要执行的服务的路径,
 /system/etc/init.preload.sh代表传给服务的参数,
 class为服务制定一个类别,该Service属于main类别,
 user执行服务前切换到用户root,该Service属于root用户,
 oneshot代表服务只启动一次,一旦关闭就不能再启动)

6、修改device/XXXX/x6818.mk文件,增加代码: 

PRODUCT_PACKAGES += init.preload.sh
PRODUCT_PACKAGES += \
    ***

目录结构如下:

device/XXXX/init.x6818.rc
device/XXXX/x6818.mk
device/XXXX/preinstall/init.preload.sh
device/XXXX/preinstall/Android.mk
device/XXXX/preinstall/preload/prelod.mk
device/XXXX/preinstall/preload/***/***.apk

注:该方法预装apk跟手动安装相同,无需预先导入lib库中的.so文件

 

B)在安卓系统中预置不可卸载的应用apk,实现方法:
1、在vendor/XXXX/apps目录下建立app文件夹,在该文件夹内创建应用程序文件夹***,将应用程序***.apk放在应用程序文件夹***内
2、在vendor/XXXX/apps目录下建立Android.mk文件,增加代码:

LOCAL_PATH   :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE  := ***
LOCAL_SRC_FILES  := app/***/***.apk
LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_OWNER := XXXX
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := PRESIGNED
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE            := &&&
LOCAL_SRC_FILES         := app/&&&/&&&.apk
LOCAL_MODULE_PATH       := $(TARGET_OUT)/priv-app/
LOCAL_MODULE_CLASS      := APPS
LOCAL_MODULE_OWNER      := XXXX
LOCAL_MODULE_TAGS       := optional
LOCAL_CERTIFICATE       := PRESIGNED
include $(BUILD_PREBUILT)

(注:1)默认预置apk到system/app/目录,LOCAL_MODULE_PATH:= $(TARGET_OUT_APPS) 普通系统apk,不可卸载

        2)LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) 放在该目录下的apk可以卸载,卸载后,恢复出厂设置时,应用不会恢复
        3)LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app/ 放在该目录下的apk可以获得系统权限,系统核心apk,不可卸载(或者加入一句:  LOCAL_CERTIFICATE:= PRESIGNED)。
        4)?LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app, 预置APK使得用户可以卸载,并且恢复出厂设置时能够恢复?自测试不管用啊)
 
对于包含lib库文件的apk,还需要根据预置目标路径,在mk脚本文件中做不同的处理:
情况一:对于预置到data/app目录下的apk,包括可恢复和不可恢复(即上面的3、4情况)可以不用手动添加lib库,apk在首次运行时,会自动将吱声的lib库抽取安装到自身的根目录。
情况二:对于预置到system/app/和system/priv-app目录下面的apk(即上面的1、2情况)因为在android系统中。system分区是不允许应用执行写操作的,因此需要在Android.mk脚本中进行配置,手动添加lib库文件到编译环境,以便lib库文件在编译之后拷贝到对应编译后的apk目录下,否则apk执行时会因为找不到lib库而报错。方法为:手动解压取出lib文件中的库文件到当前apk的编译目录,在Android.mk中添加并配置变量(注意路径对应):PRODUCT_COPY_FILES += \ vendor/9tripod/apps/app/itms/lib/libbsdiffjni.so:system/lib/libbsdiffjni.so

3、在vendor/XXXX/apps目录下建立nxapps.mk文件,增加代码

PRODUCT_PACKAGES += \
 ***  
PRODUCT_COPY_FILES += \
 vendor/XXXX/apps/app/***/lib/###1.so:system/priv-app/***/lib/arm/###1.so\
 vendor/XXXX/apps/app/***/lib/###2.so:system/priv-app/***/lib/arm/###2.so

(注:需要在该文件中预先导入lib库中的.so文件) 

 
4、在device/XXXX/x6818/device.mk文件,增加代码,这样安卓系统就会编译nxapp.mk文件:

$(call inherit-product-if-exists, vendor/XXXX/apps/nxapps.mk)