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

FROM:http://blog.csdn.net/hbk320/article/details/46822815

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

预装的条件:

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

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

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

[html]  view plain  copy
  1. System/app  
  2. System/priv-app  
  3. 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”分区下面”

由于我是使用烧录脚本进行烧写,所以可以修改烧录脚本:

[html]  view plain  copy
  1. +function copy_apk_to_data  
  2. +{  
  3. +   echo "copy apk to /data/"  
  4. +   umount ${node}* &> /dev/null  
  5. +   mkdir /mnt/android_image  
  6. +   mount ${node}${part}4 /mnt/android_image  
  7. +   mkdir /mnt/android_image/app  
  8. +   cp -rf ../ESFileExplorer_218.apk /mnt/android_image/app  
  9. +   sync  
  10. +   umount ${node}* &> /dev/null  
  11. +   rm -r /mnt/android_image  
  12. +   echo "copy apk to /data/ finish"  
  13. +}  
  14. +  
  15.  function format_android  
  16.  {  
  17.     echo "formating sdcard"  
  18. @@ -146,6 +161,8 @@ function flash_android  
  19.      if [ "${android}" -ne "1" ]; then      
  20.         copy_image_to_data    
  21.      fi  
  22. +   copy_apk_to_data  
  23.  }  

脚本内容不详细解释,大家可以去详细看看。

接下来修改 init.rc 文件,

[html]  view plain  copy
  1.      mkdir /data/app-asec 0700 root root  
  2.      mkdir /data/app-lib 0771 system system  
  3. -    mkdir /data/app 0771 system system  
  4. +#    mkdir /data/app 0771 system system  
  5. +   chown system system /data/app  
  6. +   chmod -R 0771 /data/app  
  7. +##################################################  
  8.      mkdir /data/app/ing 0771 root root  
  9.      mkdir /data/property 0700 root root  
  10.      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 文件里面做拷贝动作:

[html]  view plain  copy
  1. <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 里面添加服务:

[html]  view plain  copy
  1. +service install-app /system/bin/install-app.sh  
  2. +   class main  
  3. +   oneshot  
在system.proc里面申请属性:

[html]  view plain  copy
  1. +persist.sys.first_run=1  
 编写脚本文件:

[html]  view plain  copy
  1. #!/system/bin/sh  
  2. FLAG=$(getprop persist.sys.first_run)  
  3. #FLAG=$?  
  4. if [ 1 -eq $FLAG ];then  
  5.     setprop persist.sys.first_run 0  
  6.     busybox cp /system/user/app/ESFileExplorer_218.apk /data/app/ESFileExplorer_218.apk  
  7.     chmod 777 /data/app/ESFileExplorer_218.apk  
  8. fi  

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

        use BUILD_PREBUILT instead!.  Stop.

因为在Makefile 里面会对拷贝apk 的动作进行判断,执行把这几行代码注释掉即可:

[html]  view plain  copy
  1. -define check-product-copy-files  
  2. -$(if $(filter %.apk, $(1)),$(error \  
  3. -    Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))  
  4. -endef  
  5. +#define check-product-copy-files  
  6. +#$(if $(filter %.apk, $(1)),$(error \  
  7. +#    Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))  
  8. +#endef  
好,两种预装apk的方法到此讲述完毕。

你可能感兴趣的:(Android)