Mac OS下Java程序化执行Android设备ADB命令失败求助
我之前也踩过这个坑!问题核心出在**shell重定向符号>**的处理逻辑上:当你在终端手动执行命令时,是系统的shell(Mac上默认是zsh/sh)帮你解析了>,把adb的输出重定向到指定文件;但Java的Runtime.exec()直接调用的是adb进程,它会把>和后面的路径当成adb的命令参数,而不是交给shell处理,自然就不会生成你想要的文件了,而且因为没有语法错误,所以也不会抛出异常。
下面给你两种靠谱的解决方案,按需选择:
方案1:通过Shell执行完整命令
直接让Mac的shell来处理整个命令,用/bin/sh -c(或/bin/zsh -c,取决于你的默认shell)把完整命令包裹起来,并且用字符串数组传递参数(避免空格等特殊字符导致的拆分问题):
// 保存截图到Mac本地 Process process = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "adb exec-out screencap -p > /Users/dmytro/Documents/other/1.png" }); // 等待命令执行完成,还可以检查退出码排查问题 int exitCode = process.waitFor(); if (exitCode != 0) { BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line; while ((line = errReader.readLine()) != null) { System.err.println("执行错误:" + line); } }
同样的逻辑可以套用到其他adb命令上:
// 保存logcat到本地文件 Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "adb logcat > /Users/dmytromynziak/Documents/other/log.txt" }); // 保存截图到Android设备存储 Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "adb exec-out screencap -p > /sdcard/1.png" });
方案2:手动处理输入输出流(跨平台更可控)
如果你不想依赖系统shell,也可以自己读取adb的输出流,再写入到目标文件——这种方式在Windows和Mac上都能正常工作,还能更灵活地控制输出内容:
比如保存截图到Mac本地:
Process process = Runtime.getRuntime().exec("adb exec-out screencap -p"); InputStream inputStream = process.getInputStream(); FileOutputStream outputStream = new FileOutputStream("/Users/dmytro/Documents/other/1.png"); // 逐块读取输出并写入文件 byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } // 记得关闭资源 inputStream.close(); outputStream.close(); process.waitFor();
对于logcat这种持续输出的命令,建议开一个单独线程来读取:
Process process = Runtime.getRuntime().exec("adb logcat"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); FileWriter writer = new FileWriter("/Users/dmytromynziak/Documents/other/log.txt"); // 启动线程异步读取logcat输出 new Thread(() -> { String line; try { while ((line = reader.readLine()) != null) { writer.write(line + "\n"); writer.flush(); // 确保内容实时写入文件 } } catch (IOException e) { e.printStackTrace(); } finally { try { reader.close(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); // 需要停止logcat时,调用process.destroy();
额外小建议:优先用ProcessBuilder替代Runtime.exec
ProcessBuilder比Runtime.exec更强大,能更方便地设置工作目录、环境变量,也更容易管理进程的输入输出,推荐你后续开发中使用:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "adb exec-out screencap -p > /Users/dmytro/Documents/other/1.png"); // 可选:设置命令执行的工作目录 // pb.directory(new File("/Users/dmytro/Documents/other")); Process process = pb.start(); int exitCode = process.waitFor(); // 处理执行结果...
内容的提问来源于stack exchange,提问作者dmytro Minz
相关产品推荐
相关产品推荐

