FROM:http://blog.csdn.net/hbk320/article/details/46822815
如果厂家代码完善的话,平时拿到厂家的BSP,需要预装apk的时候,只需往预定好的目录拷贝apk即可。但如果自己手动实现起来并不见得那么简单。所以这里为大家介绍两种实现方法。
预装的条件:
出厂时候装上apk,需要删除apk的时候可以删除。
在Android 下,除了使用android自带的apk安装程序进行安装apk外,对开发人员而言,可以使用 adb install 命令进行安装。
但要求是出厂预装,所以有三种方式可以实现,就是分别把apk放到以下目录下:
- System/app
- System/priv-app
- Data/app
System/app 相信比较常用。源码out目录下的“system/app” 下,源码编译的时候,系统自带的许多apk都会放到这目录下来。不过此目录下的apk,用户不能通过 uinstall 的方式卸载,所以这种方式不能通过。
System/priv-app ,跟 “system/app”相类似。他们的区别主要是 “system/priv-app” 主要存放是系统的核心组件,如Settings.apk,而“system/app”是系统app 。其两者的相同之处是必须要root 才能把 apk 删除,用户是不具备这样的权限。
所以前两种方式安装apk不可行。
所以,最后的方法是,只能把apk 放在“data/app”目录下。
在讲解决方案前,先来讲一种失败的方案:
可能有一些人会想到如下操作:
1、 在 mk 文件 COPY 动作的时候加上一句:
Xxx.apk:data/app
2、 重新编译system.img,然后烧录系统。
可是,当烧写完系统后,发现 “data/app”下空空如也,没有发现apk任何蛛丝马迹。
这种方式不可行,原因是没有搞清楚img 文件跟系统分区之间的关系:system.img 最终是会烧录到system 分区下,而烧录到 system 分区下的文件是不会在 data 分区生效的。详细情况可以研究android 的烧写脚本,看看分区跟 img 之间的关系。
经过探讨,这里提出两种实现方法。
方法一:通过烧录的方式,把apk烧录到“data/app”下。
安照上面所说的,那把apk 拷贝到“userdata.img”里面,然后烧录到 data 分区下不就可以了吗?
可以说,想法是好的,但是一般IC厂家都会把 data 分区分配较大的容量,所以,如果重新烧写“userdata.img”的话,开机就会发现,data 分区“缩水了”,所以不能这样实现。
接下来,方案一是在烧录的时候,“把apk拷贝到“data”分区下面”
由于我是使用烧录脚本进行烧写,所以可以修改烧录脚本:
- +function copy_apk_to_data
- +{
- + echo "copy apk to /data/"
- + umount ${node}* &> /dev/null
- + mkdir /mnt/android_image
- + mount ${node}${part}4 /mnt/android_image
- + mkdir /mnt/android_image/app
- + cp -rf ../ESFileExplorer_218.apk /mnt/android_image/app
- + sync
- + umount ${node}* &> /dev/null
- + rm -r /mnt/android_image
- + echo "copy apk to /data/ finish"
- +}
- +
- function format_android
- {
- echo "formating sdcard"
- @@ -146,6 +161,8 @@ function flash_android
- if [ "${android}" -ne "1" ]; then
- copy_image_to_data
- fi
- + copy_apk_to_data
- }
脚本内容不详细解释,大家可以去详细看看。
接下来修改 init.rc 文件,
- mkdir /data/app-asec 0700 root root
- mkdir /data/app-lib 0771 system system
- - mkdir /data/app 0771 system system
- +# mkdir /data/app 0771 system system
- + chown system system /data/app
- + chmod -R 0771 /data/app
- +##################################################
- mkdir /data/app/ing 0771 root root
- mkdir /data/property 0700 root root
- mkdir /data/ssh 0750 root shell
因为在烧录的时候已经创建了 “data/app”目录,所以在init.rc里面就不需要重新创建。
方法一在这里已经可以满足需求,不过仔细考虑,通常情况下,我们在编译image 的时候普遍的做法是一个 image 已经包括所有的功能,不必需要一个apk 独立烧写,所以有必要提出第二种方式来实现。
方法二:
一般我们烧写的image里面都包括system.img 所以,我们想必首先把apk往system.img里面存放。
总体思路:
首先在mk 文件里面把apk 拷贝到out/system/xxx 的一个目录下,然后init.rc 里面启动一个服务,服务的内容就是从out/system/xxx 目录下,把 apk 文件拷贝到“data/app”下。
但这种情况下,会发现,如果在系统运行的时候把 预装的apk 卸载掉,第二次开机的时候,apk会重新被预装上。其原因是 在 init.rc 里面的服务每次开机都会启动,都会从 out/system/xxx 目录下把apk 拷贝到“data/app”下。
那么我们要做的是,只要升级起来拷贝一次,第二次开机就不会进行拷贝动作。在这里,可以通过设置android属性来完成。下面是具体的实现过程:
首先,在mk 文件里面做拷贝动作:
- <p>- device/vendor/xxx/audio_effects.conf:system/vendor/etc/audio_effects.confp><p>+ device/vendor/xxx/audio_effects.conf:system/vendor/etc/audio_effects.conf\p><p>+ device/vendor/xxx/apps/ESFileExplorer_218.apk:system/user/app/ESFileExplorer_218.apk\p><p>+ device/vendor/xxx/install-app.sh:system/bin/install-app.shp>
然后是在 init.rc 里面添加服务:
- +service install-app /system/bin/install-app.sh
- + class main
- + oneshot
在system.proc里面申请属性:
编写脚本文件:
- #!/system/bin/sh
- FLAG=$(getprop persist.sys.first_run)
- #FLAG=$?
- if [ 1 -eq $FLAG ];then
- setprop persist.sys.first_run 0
- busybox cp /system/user/app/ESFileExplorer_218.apk /data/app/ESFileExplorer_218.apk
- chmod 777 /data/app/ESFileExplorer_218.apk
- fi
最后想提一下,这样修改后,在编译的时候会提示:
use BUILD_PREBUILT instead!. Stop.
因为在Makefile 里面会对拷贝apk 的动作进行判断,执行把这几行代码注释掉即可:
- -define check-product-copy-files
- -$(if $(filter %.apk, $(1)),$(error \
- - Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
- -endef
- +#define check-product-copy-files
- +#$(if $(filter %.apk, $(1)),$(error \
- +# Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
- +#endef
好,两种预装apk的方法到此讲述完毕。