android设备静默升级
还是一如既往的android开发板子,需求是静默升级。静默升级顾名思义,就是后台默默下载,在用户无感知的情况,完成APP的升级,虽说现在有热更新的技术,但是奈何需求与实际不相符合,并且必须得有用户参与,才有很大几率成功。所以还是硬着头皮去研究一波静默升级,好在android是root权限,基本的条件是有了。
现在基本思路是这样,第一,在应用启动的时候,获取版本号,然后启动下载,下载完成之后保存到指定的文件夹,这个想必对大多数搬砖工友来说,都不难,分享一个小的框架,简单易用。Aria。示例代码如下,
//开启下载 Aria.download(this) .load(bean.url) //读取下载地址 .setFilePath(Constants.FILE_APK) //设置文件保存的完整路径 .start(); //启动下载
第二,在下载完成之后,思路就是如何才能调用命令安装,一般的安装代码肯定是没戏,但是shell命令可以试试,调用这个命令就好比。在应用外触发了一个adb命令一般,命令格式是 pm install -r " + apkPath,有没有一种熟悉的感觉,哈哈。下面分享一个封装好的工具类,可以直接传命令执行即可。
private static final String COMMAND_SU = "su"; private static final String COMMAND_SH = "sh"; private static final String COMMAND_EXIT = "exit\n"; private static final String COMMAND_LINE_END = "\n"; /** * 执行shell命令 */ public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) { int result = -1; if (commands == null || commands.length == 0) { return new CommandResult(result, null, null); } Process process = null; BufferedReader successResult = null; BufferedReader errorResult = null; StringBuilder successMsg = null; StringBuilder errorMsg = null; DataOutputStream os = null; StringBuilder cmd = new StringBuilder(); try { process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); cmd.append(isRoot ? COMMAND_SU : COMMAND_SH); cmd.append(COMMAND_LINE_END); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command == null) { continue; } os.writeBytes(command); os.writeBytes(COMMAND_LINE_END); cmd.append(command); cmd.append(COMMAND_LINE_END); os.flush(); } os.writeBytes(COMMAND_EXIT); cmd.append(COMMAND_EXIT); os.flush(); result = process.waitFor(); // get command result if (isNeedResultMsg) { successMsg = new StringBuilder(); errorMsg = new StringBuilder(); 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 (Exception e) { e.printStackTrace(); } finally { try { if (os != null) { os.close(); } if (successResult != null) { successResult.close(); } if (errorResult != null) { errorResult.close(); } } catch (IOException e) { e.printStackTrace(); } if (process != null) { process.destroy(); } } /*Log.i(TAG, "execCommand: " + cmd.toString()); Log.i(TAG, "execCommand: result = " + result + ", successMsg = " + (successMsg == null ? null : successMsg.toString()) + ", errorMsg = " + (errorMsg == null ? null : errorMsg.toString()));*/ return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null : errorMsg.toString()); }/** * 运行结果 */ public static class CommandResult { //运行结果 private int result; //运行成功结果 private String successMsg; //运行失败结果 private String errorMsg; public CommandResult(int result) { this.result = result; } public CommandResult(int result, String successMsg, String errorMsg) { this.result = result; this.successMsg = successMsg; this.errorMsg = errorMsg; } public int getResult() { return result; } public void setResult(int result) { this.result = result; } public String getSuccessMsg() { return successMsg; } public void setSuccessMsg(String successMsg) { this.successMsg = successMsg; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
代码的大概逻辑就是先判断有没有root权限,大家也知道,没有这个,也没办法调用这个命令,如果有的话,就执行命令
意思为覆盖安装。安装完成之后会有结果,如果我们还想安装完成自启动,记着不是开机自启动,而是,静默升级的程序重启,
这个时候需要找一个系统广播,配合来启动一波。系统在安装包卸载重新安装的时候,会去发送系统广播,。至于想怎么样操
作,可以结合业务逻辑判断action,来操作,同样,这个广播需要静态注册,否则,你懂得
public class UpdateReceiver extends BroadcastReceiver { private static final String TAG = UpdateReceiver.class.getSimpleName(); @Override public void onReceive(Context context, Intent intent) { String packageName = intent.getDataString(); if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {//接收升级广播 Logger.e(TAG, "onReceive:升级了一个安装包,重新启动此程序"); if (packageName.equals("package:" + SystemUtil.getPackageName())) { SystemUtil.restartApp();//升级完自身app,重启自身 } } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) {//接收安装广播 Logger.e(TAG, "onReceive:安装了" + packageName); if (packageName.equals("package:" + SystemUtil.getPackageName())) { /*SystemUtil.reBootDevice();*/ } } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { //接收卸载广播 Logger.e(TAG, "onReceive:卸载了" + packageName); } }}
配置文件中来一波,静态注册
走到这一步,然后程序run一把,然后让服务器配合一波,基本就可以了。如果遇见问题,可以参照下面的踩坑记载,对了
记得在配置文件添加相关的权限。因为我这个版本相对来说是6.0,稍微低一些,如果大家在高版本的板子上遇见问题,可以留言
大家一起讨论一波,基本上都是适配权限的问题。还有就是系统签名,一定要系统签名,否则人家不认你。
下面来说一下搞这个时候遇见几个小坑。
1.首先设备是root的,这个就不用想了,不root这个功能基本不用想了。
2.第二个得启用系统签名,这样系统才能认为你是自己人,才会让你安装,以及后来的自启动,都离不开这个。
系统签名有几种方式,其中就是你找到系统的两个文件夹,自己配置一波,然后生成签名文件,配置到debug签名下面
这样你生成的就是系统签名apk,这种查了资料,稍微麻烦一些,当然大家有时间的话,那种也挺方便,在这个推荐一种傻瓜方式。主要是节省时间,一把梭,但是得注意不要弄混了安装包,
签名命令,在当前文件夹执行如下命令,第一个app-debug.apk文件是待签名之前的app,appNew.apk是签名后的app,签名成功保存在当前文件夹下, 示例命令,java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk appNew.apk。
下面是一个朋友整理的资源,分享一波,里面有签名工具
链接:https://pan.baidu.com/s/18zQucxlvWHLkPNSVXlXKiw
提取码:bo8c
更多相关文章
- Android系统权限
- android的Log组件和logcat命令
- Android逆向之旅---带你爆破一款应用的签名验证问题
- 学习笔记(一)Android(安卓)的简介
- 编译Android源码致命错误解决方案
- android 逆向工程
- Service与Android系统实现(1)-- 应用程序里的Service(二)
- 手机杂谈
- Android(安卓)集成微信支付和支付宝支付工具类