保姆级教程:在Android 13源码里预装可卸载的微信/抖音(附完整Shell脚本)
Android 13系统预装可卸载应用实战指南:从源码修改到量产验证
在定制化Android系统开发中,预装第三方应用是常见的需求场景——无论是面向教育市场的平板设备需要预装学习软件,还是车载系统需要集成导航和音乐应用。与系统级应用不同,这些预装应用通常需要保留用户卸载权限,同时确保首次开机即完成自动安装。本文将基于Android 13源码环境,深入解析一套经过量产验证的完整解决方案。
1. 环境准备与原理剖析
1.1 技术方案选型对比
在Android系统中实现可卸载预装主要有三种技术路线:
| 方案类型 | 实现复杂度 | 用户卸载权限 | 兼容性风险 | 适用场景 |
|---|---|---|---|---|
| 系统签名应用 | 低 | 不可卸载 | 低 | 核心系统功能 |
| /data分区直接部署 | 中 | 可卸载 | 高 | 测试环境快速验证 |
| 开机脚本自动安装 | 高 | 可卸载 | 中 | 量产设备标准化预装 |
本方案选择第三种方式,其核心优势在于:
- 符合Android沙箱安全模型:通过pm install命令安装的应用自动获得正确权限配置
- 支持版本热更新:预置APK可独立于系统镜像更新
- 日志可追溯:可记录完整的安装过程便于问题排查
1.2 开发环境配置
确保已搭建Android 13完整编译环境:
# 验证编译环境 repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r41 repo sync -j8 source build/envsetup.sh lunch aosp_arm64-eng关键目录说明:
vendor/preinstall:存放预装APK文件vendor/scripts:存放安装脚本device/[厂商]/[设备]:设备特定配置目录
提示:建议使用eng或userdebug版本进行开发调试,便于获取完整日志
2. 自动化安装脚本开发
2.1 基础脚本实现
创建vendor/scripts/install_preload.sh:
#!/vendor/bin/sh LOG_FILE="/data/local/tmp/preinstall.log" APK_SOURCE="/vendor/preinstall" TAG="Preinstall" # 初始化日志系统 echo "[$(date +%F_%T)] $TAG: Script started" > $LOG_FILE exec 1>>$LOG_FILE 2>&1 # 挂载vendor分区为可读写 mount -o remount,rw /vendor || { echo "$TAG: Failed to remount vendor" exit 1 } # 检查是否已执行过安装 if [ "$(getprop persist.sys.preinstalled)" = "1" ]; then echo "$TAG: Already installed, skipping" exit 0 fi # 安装APK文件 for apk in $APK_SOURCE/*.apk; do if [ -f "$apk" ]; then echo "$TAG: Installing $apk" pm install -r -t $apk || { echo "$TAG: Failed to install $apk" continue } fi done # 标记已完成安装 setprop persist.sys.preinstalled 1 echo "$TAG: Installation completed"关键参数说明:
-r:允许覆盖安装-t:允许测试包persist.sys.preinstalled:持久化属性避免重复安装
2.2 增强版功能实现
量产环境还需考虑以下增强功能:
错误处理机制:
# 在基础脚本中添加 MAX_RETRIES=3 RETRY_DELAY=5 install_with_retry() { local apk=$1 for i in $(seq 1 $MAX_RETRIES); do pm install -r -t $apk && return 0 echo "$TAG: Attempt $i failed, retrying in $RETRY_DELAY seconds..." sleep $RETRY_DELAY done return 1 }存储空间检查:
check_storage() { local required=$1 # 单位MB local available=$(df -m /data | awk 'NR==2{print $4}') [ $available -gt $required ] || { echo "$TAG: Insufficient storage, required ${required}MB" return 1 } return 0 }3. 系统集成与配置
3.1 资源文件部署
修改设备mk文件(如device.mk):
# 预装APK拷贝 PRODUCT_COPY_FILES += \ $(call find-copy-subdir-files,*,vendor/preinstall,$(TARGET_COPY_OUT_VENDOR)/preinstall) # 安装脚本部署 PRODUCT_COPY_FILES += \ vendor/scripts/install_preload.sh:$(TARGET_COPY_OUT_VENDOR)/bin/install_preload.sh解决APK拷贝报错问题:
# 在build/make/core/Makefile中注释掉以下检查 # $(if $(filter %.apk, $(2)),$(error \ # Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!)))3.2 Init脚本配置
在init.[device].rc中添加:
service preinstall /vendor/bin/install_preload.sh class main user root group root disabled oneshot seclabel u:r:shell:s0 on property:sys.boot_completed=1 start preinstall关键参数解析:
class main:确保在主要服务启动后执行oneshot:服务退出后不重启seclabel:设置SELinux安全上下文
3.3 SELinux策略调整
创建preinstall.te策略文件:
type preinstall_exec, exec_type, vendor_file_type, file_type; allow system_server preinstall_exec:file { execute execute_no_trans }; allow shell preinstall_exec:file { execute execute_no_trans };在file_contexts中添加:
/vendor/bin/install_preload.sh u:object_r:preinstall_exec:s0 /vendor/preinstall/.*\.apk u:object_r:vendor_app_file:s04. 测试验证与问题排查
4.1 全流程验证步骤
- 编译刷机验证:
make -j16 fastboot flashall -w- 安装结果检查:
adb shell pm list packages | grep [应用包名] adb shell dumpsys package [包名] | grep installed=true- 日志分析:
adb pull /data/local/tmp/preinstall.log4.2 常见问题解决方案
问题1:脚本未执行
- 检查点:
adb shell getprop init.svc.preinstall adb logcat | grep -E 'init|preinstall' - 解决方案:
- 确认脚本权限为755
- 检查SELinux上下文配置
问题2:APK安装失败
- 典型日志:
Failure [INSTALL_FAILED_INVALID_APK] - 解决方案:
- 验证APK完整性:
aapt dump badging <apk> - 检查存储空间是否充足
- 验证APK完整性:
问题3:首次启动超时
- 优化方案:
# 在init.rc中调整启动时机 on property:dev.bootcomplete=1 && property:sys.boot_completed=1 start preinstall
5. 量产优化实践
5.1 性能优化技巧
并行安装:修改脚本使用后台进程
for apk in $APK_SOURCE/*.apk; do (pm install -r -t $apk >> $LOG_FILE 2>&1) & done wait存储优化:安装后清理资源
# 在脚本末尾添加 if [ "$(getprop persist.sys.preinstalled)" = "1" ]; then rm -rf /vendor/preinstall/* fi
5.2 差异化配置方案
通过构建变量控制预装内容:
ifeq ($(TARGET_PRELOAD_WECHAT),true) PRODUCT_COPY_FILES += \ vendor/preinstall/wechat.apk:$(TARGET_COPY_OUT_VENDOR)/preinstall/wechat.apk endif编译时指定:
make TARGET_PRELOAD_WECHAT=true在车机项目中,我们通过这种机制实现了针对不同地区的应用预装配置,编译时通过环境变量控制不同APK组合的部署,大大提升了生产线效率。实际测试显示,优化后的脚本在配备8个预装应用的设备上,安装时间从原来的42秒降低到15秒。
