【问题描述】
客户更新他们的apk,预装成可卸载应用,但是因为system分区空间不足,导致编译不通过
【问题分析】
system分区空间不足,最直接的方法就是扩大system分区,但是项目已经定版,此时再更新分区大小,会导致无法OTA。
那么另一种方法则是裁剪Android系统原生预装的应用,根据设备类型,去裁剪掉NFC,通讯录这些应用
再或者,去掉一些lib库或者bin文件
但是,这些文件本身的大小就很小,远不够需要的空间。那么,本文采取的对策是,压缩原本预装apk为gz格式,以此来减少system分区空间消耗。然后在系统启动时,解压缩到data分区,并完成静默安装
【修改对策】
if [ ! -d "/data/preinstall/" ]; then
mkdir -p /data/preinstall
chmod 777 /data/preinstall
for file in /system/preInstallApk/*.gz; do
if [ -f "$file" ]; then
cp "$file" /data/preinstall/
gunzip -f "/data/preinstall/$(basename "$file")"
echo $(basename "$file" .gz)
chmod 777 "/data/preinstall/$(basename "$file" .gz)"
fi
done
fi
private void installAppFromData(String pkgName,String apkName){
if (!isAPPInstall(pkgName)) {
File file = new File("/data/preinstall/"+apkName+".apk");
if(file.exists()){
installApp("/data/preinstall/"+ apkName+".apk");
}
}
}
// 静默安装
public boolean installApp(String absoluteAPKPath) {
String apkPath = absoluteAPKPath;
File apkFile = new File(apkPath);
PackageManager packageManager = mContext.getPackageManager();
PackageInstaller packageInstaller = packageManager.getPackageInstaller();
SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
sessionParams.setSize(apkFile.length());
int sessionId = createSession(packageInstaller, sessionParams);
if (sessionId != -1) {
boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkPath);
if (copySuccess) {
execInstallCommand(mContext, packageInstaller, sessionId);
}
}
}
实现步骤
- 预装APK压缩:
- 在Android构建系统中添加命令,将预装的APK文件压缩为.gz格式,并将它们存放在特定目录下,如示例中的/system/preInstallApk/目录。
- 系统启动时解压缩和安装:
- 修改设备的启动脚本或添加一个初始化服务,检查/data/preinstall/目录是否存在。如果不存在,则创建该目录并设置合适的权限。
- 将/system/preInstallApk/目录下的所有.gz文件复制到/data/preinstall/目录,然后解压这些文件,准备安装。
- 对于每个解压后的APK文件,调用自定义的安装方法来完成静默安装过程。
- 静默安装实现:
- 通过调用PackageManager的PackageInstaller API来实现APK的静默安装。创建安装会话,将APK文件复制到会话中,然后执行安装命令。
【总结】
通过压缩和解压预装APK来优化system分区空间的方法,避免直接修改分区大小,尤其适用于无法通过常规OTA更新调整分区大小的场景。
当然了,最根本的做法是,从项目开始开发时,就计算好system分区所需要的大小,并且考虑未来可能的增长和更新,额外预留至少10-20%的空间。减少后续的维护成本。