本文主要介绍程序如何利用root权限静默安装(卸载)APK,如何自动选择普通安装(卸载)还是静默安装(卸载)。
1、root权限静默安装(卸载)调用
引入TrineaAndroidCommon@Github(欢迎star和fork^_^)作为你项目的library(如何拉取代码及添加公共库),或自己抽取PackageUtils.installSlient(PackageUtils.uninstallSilent)函数进行调用,系统授权管理会弹出对话框让用户选择是否允许应用获得root权限。允许的话即可静默安装。
该函数返回PackageUtils.INSTALL_SUCCEEDED表示安装成功,失败则返回相应错误码,可以得到失败的详细原因,包括文件不存在,apk无效,系统内存不足,签名不正确,缺少公共库,share user错误等等判断。
注意对于较大apk安装过程非常耗时,所以最好新启线程去调用PackageUtils.installSlient。
2、root权限静默安装实现
PackageUtils.installSlient的实现实际使用的是su pm install -r filePath命令。核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
public static final String COMMAND_SU = "su"; public static final String COMMAND_SH = "sh"; public static final String COMMAND_EXIT = "exit\n"; public static final String COMMAND_LINE_END = "\n"; 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; try { process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command == null) { continue; } // donnot use os.writeBytes(commmand), avoid chinese charset error os.write(command.getBytes()); os.writeBytes(COMMAND_LINE_END); os.flush(); } os.writeBytes(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 (IOException e) { e.printStackTrace(); } 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(); } } return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null : errorMsg.toString()); } |
其中commands为pm install -r . 从中可以看出主要就是使用su切换到root环境下,再调用pm install -r进行安装。
3、普通安装,系统权限静默安装,root权限静默安装的自动选择
查看PackageUtils源码会发现我还提供了其他几个安装函数,其中PackageUtils.install(PackageUtils.uninstall)函数会根据是否是系统应用以及是否拥有root权限,从而确定调用哪种安装方式(普通安装方式、root静默安装方式还是系统权限静默安装),源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/** * install according conditions * <ul> * <li>if system application or rooted, see {@link #installSilent(Context, String)}</li> * <li>else see {@link #installNormal(Context, String)}</li> * </ul> * * @param context * @param filePath * @return */ public static final int install(Context context, String filePath) { if (!PackageUtils.isSystemApplication(context) && !ShellUtils.checkRootPermission()) { return installNormal(context, filePath) ? INSTALL_SUCCEEDED : INSTALL_FAILED_INVALID_URI; } return installSilent(context, filePath); } |
如果是系统应用记得添加<uses-permission android:name=”android.permission.INSTALL_PACKAGES” />权限,从而走普通安装方式,不用申请root权限进行静默安装。
4、PackageUtils 实现静默卸载应用
静默安装完成后 怎么监听完成安装啊
我引用了你的公共库!直接调方法就会静默安装了?
android 4.0以上系统也适用吗?
每次都提示超级用户请求
得看你系统的root权限管理软件怎么做的,如果他提供”记住该选择”这个checkbox,那么选择后,不会每次提示,如果不提供就没办法了
已经记住了,但豌豆加只提示一次,下次安装都不提示。不知道它是怎么做的。
我在很多系统上用过都没有问题
你好 我qq 1349425973急需非root静默安装 在您那购买
没做过,网上有通过反射去实现的示例,但不一定能绕过权限认证
Pingback: Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类) | itjoyee
Pingback: Android开发中常用的工具类 | 稀米糊
你好,我有几个初级的问题一直没搞明白,想请教一下。
1.所谓系统应用是不是通过编译源码编出来的?还有没有其他的方法制造系统应用?
2.因为我把普通应用生成的apk通过adb放到了system/app下面,但是运行pm install 还是会报Caused by: java.lang.SecurityException: Neither user 10060 nor current process has android.permission.INSTALL_PACKAGES.的权限错误,说明并不是放到system/app下面就会有系统的权限。如何能够把普通应用变成一个系统应用呢?我看网上说需要添加shareId和系统的签名,是这样吗?
这个错误返回值呢?
请问是什么呢,谢谢
08-05 15:21:32.668: E/PackageUtils(16273): successMsg:, ErrorMsg:Segmentation fault
应该是apk文件名的问题,可能含有中文,改成aaa.apk试试
问题依旧呢?版主你有交流群吗?这样交流好难啊
群暂时没有,加我qq吧,717763774
写的很好,但我想问下,为什么调用pm install -r -s 可安装成功,但却并没有强制安装应用到sdcard中呢?依然是默认安装到内存。
我在install 之前先 setInstallLocation 2 设置默认安装位置,安装后也仍然安装到了内存中。 请问怎样才能静默安装到sd卡中?谢谢!
几个可以debug的点
1、shell命令中pm install -r -s看是否成功。
2、该应用是否支持安装到sd卡,反编译查看AndroidManifest.xml中的android:installLocation字段。
3、pm setInstallLocation 2后用pm getInstallLocation检查是否设置成功,可参考force apps to install to SD card
可以确定2个命令都是成功的。却仍然安装到了手机内存中。
另外也可以确定该应用是可以移动到sdcard的,调用系统应用程序信息界面的 app2sd 也是可成功移动到sdcard的。
我想调用pm实现软件搬家的功能,但pm install -r -s 却无法将app reinstall 到sdcard中。
望告知怎么解决这个问题,或怎样正确的实现软件搬家功能。谢谢!
这就奇怪了,按照pm install命令的help提示,-s确实是可以保留数据重装的。哈哈,我之前也准备做个软件用来搬家,一直搁置至今,目前我想到的也跟你一样pm install -r -s。你要是找到了可以解决的方法,也一定要告诉我哈
好的~