分析android预装apk以及相关的实现手段

来源:互联网 发布:java多线程面试题2017 编辑:程序博客网 时间:2024/04/29 07:40

如果厂家代码完善的话,平时拿到厂家的BSP,需要预装apk的时候,只需往预定好的目录拷贝apk即可。但如果自己手动实现起来并不见得那么简单。所以这里为大家介绍两种实现方法。

预装的条件:

         出厂时候装上apk,需要删除apk的时候可以删除。

在android 下,除了使用android自带的apk安装程序进行安装apk外,对开发人员而言,可以使用 adb install 命令进行安装。

但要求是出厂预装,所以有三种方式可以实现,就是分别把apk放到以下目录下:

System/appSystem/priv-appData/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.conf</p><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.sh</p>
 然后是在 init.rc 里面添加服务:

+service install-app /system/bin/install-app.sh+class main+oneshot
在system.proc里面申请属性:

+persist.sys.first_run=1
 编写脚本文件:

#!/system/bin/shFLAG=$(getprop persist.sys.first_run)#FLAG=$?if [ 1 -eq $FLAG ];thensetprop persist.sys.first_run 0busybox cp /system/user/app/ESFileExplorer_218.apk /data/app/ESFileExplorer_218.apkchmod 777 /data/app/ESFileExplorer_218.apkfi

最后想提一下,这样修改后,在编译的时候会提示:

        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的方法到此讲述完毕。





2 0
原创粉丝点击