你知道怎么在控制台使用ping吗?那你知道怎么在java中使用ping吗?
1.批处理文件
批处理文件大家一定不陌生。接触最多的应该就是tomcat中的start.bat或者start.sh了。bat是在windows环境下运行的批处理文件,sh则是linux的shell脚本。
2.adb指令
安卓刷机的小伙伴们肯定对adb不陌生吧?为了使用adb,我们先安装一个夜神模拟器。比如我安装在C:\Program Files\Nox\bin,那么我们先打开cmd,并且cd到C:\Program Files\Nox\bin目录中。adb指令列表可以看https://www.yeshen.com/faqs/H15tDZ6YW。我们先启动夜神模拟器。
启动完成后
我们此时在控制台输入adb devices
查看启动的夜神模拟器列表
可以看到已经启动了一个模拟器,占用了62001的端口。
3.Process类
如何在java中执行上述的指令呢?java中有一个类叫做Process,用于执行shell之类的指令,而且可以获得控制台的输出内容。
public class App { public static void main(String...args)throws Exception{ //执行指令 Process process = Runtime.getRuntime().exec("adb devices"); System.out.println("【控制台执行信息】"); System.out.println(readInputstream(process.getInputStream())); System.out.println("【控制台错误信息】"); System.out.println(readInputstream(process.getErrorStream())); } /** * 读取控制台打印的文字 * @param in * @return * @throws Exception */ public static String readInputstream(InputStream in) throws Exception{ InputStream inputStream = in; InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); StringBuilder sb = new StringBuilder(); String line = null; while((line=bufferedReader.readLine())!=null){ sb.append(line).append("\n"); } return sb.toString(); } }
执行结果如下
这是因为在程序入口下找不到adb.exe这个文件。我们只要把【adb】换成【C:\Program Files\Nox\bin\adb】就可以了。
执行结果如下
还有一种执行指令的方式就比上述的方式更加简单了。
下面要讲的是ProcessBuilder这个类。我们将main函数修改成以下样子
public static void main(String...args)throws Exception{ //执行指令 // Process process = Runtime.getRuntime().exec("C:\\Program Files\\Nox\\bin\\adb devices"); //此处利用ProcessBuilder的command方法, //值得注意的是command方法支持可变参数, //也可以使用List,只要按指令空格分开好每个指令项就OK Process process = new ProcessBuilder().command("C:\\Program Files\\Nox\\bin\\adb","devices").start(); System.out.println("【控制台执行信息】"); System.out.println(readInputstream(process.getInputStream())); System.out.println("【控制台错误信息】"); System.out.println(readInputstream(process.getErrorStream())); }
执行结果也是一样的。接下来我们也建一个Builder。
4.编写指令词典
可以看到,adb指令实在太多了。作为一个java程序员,是没必要去记住这些东西的,因为实际上我们并不常用这个东西。所以我们只好建一个指令词典了。指令词典的demo如下(我使用了lombok插件,自动生成Getter方法,不知道的同志们,请百度搜一下):
package com.zeemoo.nox.actuator.consts; import lombok.Getter; /** * 夜神模拟器的adb指令词典 * * @author zhang.shushan * @date 2018/6/8 */ @Getter public class NoxCmdDict { /** * adb脚本指令 */ public final static String ADB = "adb"; /** * 选择模拟器 */ public final static String SERVER_HOST = "-s"; /** * 模拟器列表 */ public final static String DEVICES = "devices"; /** * 安装apk */ public final static String INSTALL = "install"; /** * 从电脑发送文件到模拟器,没什么卵用,还有权限限制 */ @Deprecated public final static String PUSH = "push"; /** * 从模拟器拉取文件到电脑,没什么卵用,还有权限限制 */ @Deprecated public final static String PULL = "pull"; /** * 卸载app */ public final static String UNINSTALL = "uninstall"; /** * shell脚本指令,安卓内核为linux */ public final static String SHELL = "shell"; /** * 列举进程 */ public final static String SHELL_PS = "ps"; /** * 包含某个字符串的进程信息 */ public final static String SHELL_PS_MTH_FIND_STR ="|findStr"; /** * 包指令 */ public final static String SHELL_PM = "pm"; /** * 包指令下的列举指令 */ public final static String SHELL_PM_LIST = "list"; /** * 包指令下的列举指令选项,表示列举所有的包名 */ public final static String SHELL_PM_LIST_PACKAGES = "packages"; /** * 包指令下的列举指令选项的附加选项,表示列举所有的包名和对应的路径 */ public final static String SHELL_PM_LIST_PACKAGES_OP_NAME_AND_PATH = "-f"; /** * 获取某个应用的路径,需要填写包名 */ public final static String SHELL_PM_PATH = "path"; /** * 清除应用缓存,后面接包名 */ public final static String SHELL_PM_CLEAR_TEMP = "clear"; /** * 应用管理指令(Activity Manager),启动或关闭应用 */ public final static String SHELL_AM = "am"; /** * 启动应用,最后接上包名+“/”+Activity类名 */ public final static String SHELL_AM_START = "start"; /** * 这个选项表示如果应用启动了就直接打开后台进程,如果没启动则启动。 * 不加此选项每次调用start的时候则每次都重启应用 */ public final static String SHELL_AM_START_OP_XSTART = "-n"; /** * 关闭应用,后接包名 */ public final static String SHELL_AM_STOP = "force-stop"; /** * 杀死进程,后接包名,似乎没什么用 */ public final static String SHELL_AM_KILL = "kill"; /** * 杀死后台所有进程,似乎没什么用 */ public final static String SHELL_AM_KILL_ALL = "kill-all"; /** * shell模拟输入 */ public final static String SHELL_INPUT = "input"; /** * 模拟输入文字(不支持中文) */ public final static String SHELL_INPUT_TEXT = "text"; /** * 模拟点击按键 */ public final static String SHELL_INPUT_KEYEVENT = "keyevent"; /** * 模拟鼠标点击,后面接X,Y */ public final static String SHELL_INPUT_TAP = "tap"; /** * 模拟鼠标滑动,后面接X1,Y1,X2,Y2 */ public final static String SHELL_INPUT_SWIPE = "swipe"; /** * 截屏 */ public final static String SHELL_SCREEN_CAP = "screencap"; /** * 截屏选项,后接截屏文件输出目标 */ public final static String SHELL_SCREEN_CAP_OP_DEST = "-p"; /** * 退出shell */ public final static String SHELL_EXIT = "exit"; /** * 夜神模拟器的adb */ public final static String NOX_ADB = "nox_adb"; /** * 夜神模拟器属性设置 */ public final static String NOX_ADB_SHELL_SET_PROP = "setprop"; /** * 设置手机的纬度 */ public final static String NOX_ADB_SHELL_SET_PROP_LATITUDE = "persist.nox.gps.latitude"; /** * 设置模拟器的经度 */ public final static String NOX_ADB_SHELL_SET_PROP_LONGITUDE = "persist.nox.gps.longitude"; /** * 设置模拟器的mac地址 */ public final static String NOX_ADB_SHELL_SET_PROP_MAC = "setprop persist.nox.wifimac"; }
现在来创建一个Builder类,代码如下
package com.zeemoo.nox.actuator.service; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; import java.io.File; import java.util.ArrayList; import java.util.List; //此处使用静态引入指令词典,可以试着删去这一行,看看有什么区别 import static com.zeemoo.nox.actuator.consts.NoxCmdDict.*; /** * 功能指令构建 * * @author zhang.shushan * @date 2018/6/8 */ @Setter @AllArgsConstructor @NoArgsConstructor public class NoxCmdBuilder { /** * 夜神模拟器的根目录 */ private String noxPath; /** * 给指令添加指定模拟器 * @param cmds * @param host * @return */ public List<String> addHost(List<String> cmds,String host){ if(host!=null&&"".equals(host)){ cmds.add(1, SERVER_HOST); cmds.add(2,host); } return cmds; } /** * 筛选字符进程 * @param example * @return */ public List<String> listProcess(String example){ List<String> cmds=listPackageName(); cmds.add(SHELL_PS_MTH_FIND_STR); cmds.add(example); return cmds; } /** * 列举所有的进程 * @return */ public List<String> listProcess(){ List<String> cmds = this.shellModal(); cmds.add(SHELL_PS); return cmds; } /** * 列举所有模拟器 * @return */ public List<String> devices(){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+File.separator+ NOX_ADB); cmds.add(DEVICES); return cmds; } /** * 启动夜神模拟器 * @return */ public String startNox(){ return noxPath+File.separator+"nox.exe"; } /** * 截屏 * @param vitualBoxFilePath * @return */ public List<String> screenCap(String vitualBoxFilePath){ List<String> cmds = new ArrayList<>(); cmds.add(SHELL_SCREEN_CAP); cmds.add(SHELL_SCREEN_CAP_OP_DEST); cmds.add(vitualBoxFilePath); return cmds; } /** * 模拟滑动屏幕 * @param x1 * @param y1 * @param x2 * @param y2 * @return */ public List<String> swipe(int x1,int y1,int x2,int y2){ List<String> cmds = this.inputModal(); cmds.add(SHELL_INPUT_SWIPE); cmds.add(String.valueOf(x1)); cmds.add(String.valueOf(y1)); cmds.add(String.valueOf(x2)); cmds.add(String.valueOf(y2)); return cmds; } /** * 模拟点击 * @param x * @param y * @return */ public List<String> click(int x,int y){ List<String> cmds = this.inputModal(); cmds.add(SHELL_INPUT_TAP); cmds.add(String.valueOf(x)); cmds.add(String.valueOf(y)); return cmds; } /** * 模拟按键 * @param keys 按键 * @return */ public List<String> pressKey(List<String> keys){ List<String> cmds = this.inputModal(); cmds.add(SHELL_INPUT_KEYEVENT); cmds.addAll(keys); return cmds; } /** * 文本输入,不支持中文 * @param text * @return */ public List<String> inputText(String text){ List<String> cmds = this.inputModal(); cmds.add(SHELL_INPUT_TEXT); cmds.add(text); return cmds; } /** * 输入模式 * @return */ private List<String> inputModal() { List<String> cmds = this.shellModal(); cmds.add(SHELL_INPUT); return cmds; } /** * 杀死后台所有进程 * @return */ public List<String> killAllAppProcess(){ List<String> cmds = this.activityManager(); cmds.add(SHELL_AM_KILL_ALL); return cmds; } /** * 杀死某个后台进程 * @param pkgNm * @return */ public List<String> killAppProcess(String pkgNm){ List<String> cmds = this.activityManager(); cmds.add(SHELL_AM_KILL); cmds.add(pkgNm); return cmds; } /** * 停止app * @param pkgName * @return */ public List<String> stopApp(String pkgName){ List<String> cmds = this.activityManager(); cmds.add(SHELL_AM_STOP); cmds.add(pkgName); return cmds; } /** * 启动app * @param pkgName * @param activity * @return */ public List<String> startApp(String pkgName,String activity){ List<String> cmds = this.activityManager(); cmds.add(SHELL_AM_START); cmds.add(SHELL_AM_START_OP_XSTART); cmds.add(pkgName+"/"+activity); return cmds; } /** * 获取某个应用的路径 * @param pkgName * @return */ public List<String> getAppPath(String pkgName){ List<String> cmds = this.packageManager(); cmds.add(SHELL_PM_PATH); cmds.add(pkgName); return cmds; } /** * * @return */ public List<String> listPackageNameAndPath(){ List<String> cmds = this.listPackageName(); cmds.add(SHELL_PM_LIST_PACKAGES_OP_NAME_AND_PATH); return cmds; } /** * 列举所有的包名 * @return */ public List<String> listPackageName(){ List<String> cmds=this.packageManager(); cmds.add(SHELL_PM_LIST); cmds.add(SHELL_PM_LIST_PACKAGES); return cmds; } /** * 包操作指令 * @return */ private List<String> packageManager(){ List<String> cmds = this.shellModal(); cmds.add(SHELL_PM); return cmds; } /** * activityManager模式 * @return */ private List<String> activityManager(){ List<String> cmds = this.shellModal(); cmds.add(SHELL_AM); return cmds; } /** * 从模拟器拉取文件到电脑,有权限限制 * @param virtualBoxFilePath * @param pcFilePath * @return */ @Deprecated public List<String> pull(String virtualBoxFilePath,String pcFilePath){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+File.separator+virtualBoxFilePath); cmds.add(PULL); cmds.add(virtualBoxFilePath); cmds.add(pcFilePath); return cmds; } /** * 推送文件到模拟器,有权限限制 * @param pcFilePath * @param vitualBoxFilePath * @return */ @Deprecated public List<String> push(String pcFilePath,String vitualBoxFilePath){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+ File.separator+ NOX_ADB); cmds.add(PUSH); cmds.add(pcFilePath); cmds.add(vitualBoxFilePath); return cmds; } /** * 卸载app * @param packageName * @return */ public List<String> uninstall(String packageName){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+ File.separator+ NOX_ADB); cmds.add(UNINSTALL); cmds.add(packageName); return cmds; } /** * 安装app * @param apkPath * @return */ public List<String> install(String apkPath){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+ File.separator+ NOX_ADB); cmds.add(INSTALL); cmds.add(apkPath); return cmds; } /** * 设置mac地址 * @param mac * @return */ public List<String> setMac(String mac){ List<String> cmds = this.shellModal(); cmds.add(NOX_ADB_SHELL_SET_PROP); cmds.add(NOX_ADB_SHELL_SET_PROP_MAC); cmds.add(mac); return cmds; } /** * 设置经度 * @param longitude * @return */ public List<String> setLongitude(Double longitude){ List<String> cmds = this.shellModal(); cmds.add(NOX_ADB_SHELL_SET_PROP); cmds.add(NOX_ADB_SHELL_SET_PROP_LONGITUDE); cmds.add(longitude.toString()); return cmds; } /** * 设置模拟器纬度 * @param latitude * @return */ public List<String> setLatitude(Double latitude){ List<String> cmds = this.shellModal(); cmds.add(NOX_ADB_SHELL_SET_PROP); cmds.add(NOX_ADB_SHELL_SET_PROP_LATITUDE); cmds.add(latitude.toString()); return cmds; } /** * shell模式,设置模拟器属性之类的 * @return */ private List<String> shellModal(){ List<String> cmds = new ArrayList<>(); cmds.add(noxPath+ File.separator+ NOX_ADB); cmds.add(SHELL); return cmds; } /** * shell模式,清除缓存 * @return */ public List<String> clearTemp(String pckName) { List<String> cmds = this.shellModal(); cmds.add(SHELL_PM_CLEAR_TEMP); cmds.add(pckName); return cmds; } }
我们来测试一下。修改main方法如下:
public static void main(String...args)throws Exception{ NoxCmdBuilder noxCmdBuilder = new NoxCmdBuilder("C:\\Program Files\\Nox\\bin"); System.out.println(noxCmdBuilder.listPackageName()); }
输出结果
[C:\Program Files\Nox\bin\nox_adb, shell, pm, list, packages]
直接将这个list放入ProcessBuilder中使用,就可以获得所有的包名了。我们来试一下。修改main如下
public static void main(String... args) throws Exception { NoxCmdBuilder noxCmdBuilder = new NoxCmdBuilder("C:\\Program Files\\Nox\\bin"); Process start = new ProcessBuilder().command(noxCmdBuilder.listPackageName()).start(); //此处注意的是,读取流信息的时候,有可能流对象太大, //不能一次性读完,导致获取的字符串顺序错乱或缺失的问题, //所以我们等程序执行完毕之后再去读取 //waitFor会让线程阻塞,直至process执行完毕 start.waitFor(); System.out.println(readInputstream(start.getInputStream())); }