作为底层人员开发android测试程序,经常用到一些脚本来开发一些功能,集成到APP中。
如果使用编码来实现shell脚本,一来非常麻烦,二来效率低,三来很多功能根本实现不了。
这里很多脚本需要root来运行,那么作为开发的设备,首先得确保能正常获取到ROOT权限。
ROOT的方法具体的设备均不相同,但原理都是通的。
1. 破解和集成su命令
2. 权限管理软件如:SuperSU
具体破解的方法就自行百度吧。
JAVA: shell类
import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; /** * ShellUtils * <ul> * <strong>Check root</strong> * <li>{@link ShellUtils#checkRootPermission()}</li> * </ul> * <ul> * <strong>Execte command</strong> * <li>{@link ShellUtils#execCommand(String, boolean)}</li> * <li>{@link ShellUtils#execCommand(String, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean, boolean)}</li> * </ul> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 */ public class ShellUtils { 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"; //add public static final String COMMAND_LINE_NEXT_LINE = "\r\n"; private ShellUtils() { throw new AssertionError(); } /** * check whether has root permission * * @return */ public static boolean checkRootPermission() { return execCommand("echo root", true, false).result == 0; } /** * execute shell command, default return result msg * * @param command command * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String command, boolean isRoot) { return execCommand(new String[] {command}, isRoot, true); } /** * execute shell commands, default return result msg * * @param commands command list * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(List<String> commands, boolean isRoot) { return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true); } /** * execute shell commands, default return result msg * * @param commands command array * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String[] commands, boolean isRoot) { return execCommand(commands, isRoot, true); } /** * execute shell command * * @param command command * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) { return execCommand(new String[] {command}, isRoot, isNeedResultMsg); } /** * execute shell commands * * @param commands command list * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) { return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, isNeedResultMsg); } /** * execute shell commands * * @param commands command array * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return <ul> * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and * {@link CommandResult#errorMsg} is null.</li> * <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li> * </ul> */ 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).append(COMMAND_LINE_NEXT_LINE); } while ((s = errorResult.readLine()) != null) { errorMsg.append(s).append(COMMAND_LINE_NEXT_LINE); } //返回信息 使用换行 if(successMsg!=null&&successMsg.length()>COMMAND_LINE_NEXT_LINE.length()){ successMsg.delete(successMsg.length()-COMMAND_LINE_NEXT_LINE.length(), successMsg.length()); } if(errorMsg!=null&&errorMsg.length()>COMMAND_LINE_NEXT_LINE.length()){ errorMsg.delete(errorMsg.length()-COMMAND_LINE_NEXT_LINE.length(), errorMsg.length()); } } } 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()); } /** * result of command * <ul> * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in * linux shell</li> * <li>{@link CommandResult#successMsg} means success message of command result</li> * <li>{@link CommandResult#errorMsg} means error message of command result</li> * </ul> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 */ public static class CommandResult { /** result of command **/ public int result; /** success message of command result **/ public String successMsg; /** error message of command result **/ public 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 static int run_shell(String shell[], boolean isRoot) { if (null == shell || shell.length <= 0) { return -1; } List<String> commnandList = new ArrayList<String>(); for (String s : shell) { // Log.d(TAG, s); commnandList.add(s); } CommandResult result = ShellUtils.execCommand(commnandList, isRoot); commnandList.clear(); if (result.result == 0) { Log.d(TAG, "successMsg: " + result.successMsg); } else { Log.d(TAG, "error: " + result.errorMsg); } return result.result; }
String cmd1[]={ "rm /sdcard/shj*.log", }; run_shell(cmd1,true);
这里的封装单单是为了运行命令而封装的,当命令成功返回,需要参考 返回信息。
像ls这类命令,返回信息就非常重要,用法就不是这样的了。
至于为什么我要封装成命令数组,在于有些命令非常麻烦,居然不支持绝对路径,busybox中tar命令,居然没有-P这个参数。
当然很多命令适合封装成脚本来运行,就得先chmod +x 然后在 执行,所以数组也蛮合理的。
这里的boolean值,就是要说是否使用ROOT权限来执行这个命令,
如果这里填true,已经root并安装supersu会弹出是否允许的提示框。
当然觉得这个提示很烦,可以在superSU设置为默认允许即可。