基于业务需要,Android平板用户应用要变成系统应用,而且是桌面应用的唯一入口(关机开机后的应用界面)。
平板root之后,基于应用的改变为系统都有现成的说明,主要核心是将系统签名后的应用 adb push *****.apk /system/app中,当提示
adb: error: failed to copy 'ShenYue.apk' to '/system/app/*****.apk': remote Read-only file system
******apk: 0 files pushed. 25.1 MB/s (131056 bytes in 0.005s)
主要是权限未开放,需要挂载处理 直接
adb shell
mount -o remount,rw /system
exit
重新输入adb push *****.apk /system/app 等到传输完,打开手机应用快的话,你会看到应用突然就冒出来了,不行你就重启。
下面重点来了,用户应用改变成系统应用之后,升级咋办?
一开始思路,就是想办法下载的应用直接覆盖/system/app下目标apk, 问题开始出来了,之前在用户应用里面实现的下载模块提示下载失败,打开目录查阅发现根本没有对应的文件,原来把下载目录改成/system/app下 没有权限无法读写。
又考虑下载到公有目录下,然后直接拷贝到/system/app, 如下:
String paramString= "$ adb shell" +"\n"+ "$ su" +"\n"+ "# mount -o remount,rw /system" +"\n"+ //"# rm /system/app/ShenYue.apk" +"\n"+ *//* "# exit" +"\n"+ "$ adb push " + Constants.FILE_UPDATE_CLIENT_SAVE_PATH + Constants.FILE_CLIENT_NAME*//**//*//**//*data/DeepRead/ShenYue.apk*//**//* +" /system/app/ShenYue.apk" +"\n"+ "$ adb shell" +"\n"+ "$ su" +"\n"+*//* " cp " + Constants.FILE_UPDATE_CLIENT_SAVE_PATH + Constants.FILE_CLIENT_NAME + " /system/app" + "\n" ; // "# mount -o remount,ro /system" +"\n"+ //"# am start -n com.yuanzong.deepread/.activity.SplashActivity" +"\n"+ // "# exit" +"\n"+ // "$ exit"; if(RootCmd.haveRoot()){ if(RootCmd.execRootCmdSilent(paramString)==-1){ Toast.makeText(SplashActivity.this, "安装不成功", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(SplashActivity.this, "安装成功", Toast.LENGTH_LONG).show(); // System.exit(0); } }
走不通,因为发现无论是rm cp 还是adb push 都无法改变当前版本的信息。
各种资料查阅,测试验证之后,发现静默安装可以解决问题
/** * install slient * * @param filePath * @return 0 means normal, 1 means file not exist, 2 means other exception error */ public static int installSilent(String filePath) { File file = new File(filePath); if (filePath == null || filePath.length() == 0 || file == null || file.length() <= 0 || !file.exists() || !file.isFile()) { return 1; } String[] args = { "pm", "install", "-r", filePath }; ProcessBuilder processBuilder = new ProcessBuilder(args); java.lang.Process process = null; BufferedReader successResult = null; BufferedReader errorResult = null; StringBuilder successMsg = new StringBuilder(); StringBuilder errorMsg = new StringBuilder(); int result; try { process = processBuilder.start(); successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); String s; while ((s = successResult.readLine()) != null) { successMsg.append(s); } while ((s = errorResult.readLine()) != null) { errorMsg.append(s); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (successResult != null) { successResult.close(); } if (errorResult != null) { errorResult.close(); } } catch (IOException e) { e.printStackTrace(); } if (process != null) { process.destroy(); } } // TODO should add memory is not enough here if (successMsg.toString().contains("Success") || successMsg.toString().contains("success")) { result = 0; } else { result = 2; } Logg.d(TAG, "successMsg:" + successMsg + ", ErrorMsg:" + errorMsg); return result; }
可以参考:https://blog.csdn.net/u013341672/article/details/69320412
发现一开始自己的思路就出现了问题,所以后面死胡同走不通。
不是要覆盖整个system/app里面的应用,而是走自己的一套升级流程。例如当前版本1.0.1,你首次安装通过push推进到手机里,通过静默升级(升级下载系统签名安装包的路径也要是公有的)到1.0.2之后, 你使用的一直都是1.0.2,后面再次升级也只是覆盖1.0.2,而永远都不会覆盖1.0.1。但是1.0.1还是存在的,当你通过设置页面删除应用也只是删除1.0.2或更高版本的应用, 1.0.1还是存在的。类似于恢复出厂设置的应用原理