jar包调用Runtime.getRuntime().exec无法获取bash_profile环境变量如何解决
根因分析
macOS 下桌面应用(包括 Android Studio、IntelliJ IDEA)默认启动时不会主动读取用户的 shell 配置文件(~/.bash_profile、~/.zshrc等),只会继承系统级的环境变量。你在 IDE 内直接运行调试代码时,IDE 是从你当前登录的 shell 会话启动的,所以能拿到完整的用户环境变量;但打包成插件安装到独立启动的 Android Studio 后,插件启动的 bash 子进程只能拿到极简的默认 PATH,自然找不到你配置在用户级 shell 配置里的 flutter 命令。
可行解决方案
方案1:以登录模式启动bash(最适配你的需求)
bash 的-l(即--login)参数会让进程以登录 shell 模式启动,自动加载当前用户的~/.bash_profile配置,不需要硬编码路径,也不需要修改你要执行的 shell 脚本,适配不同用户的自定义 flutter 安装路径。
只需要修改你ShellUtil中的 command 构造逻辑即可:
public static class ShellUtil { public static String runShell(String shStr) throws Exception { Process process; // 新增-l参数,以登录模式启动bash,自动加载用户bash_profile配置 String[] command = new String[] {"bash","-l","-c",shStr}; process = Runtime.getRuntime().exec(command); process.waitFor(); BufferedReader read = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; StringBuilder result = new StringBuilder(); // 建议用StringBuilder优化字符串拼接性能 while ((line = read.readLine())!=null){ result.append(line); } return result.toString(); } }
如果你的用户可能使用 macOS 默认的 zsh 作为默认 shell,可以同步提示用户将 flutter 路径配置也写入~/.zshrc,或者将命令调整为读取用户默认 shell 再启动对应登录模式进程,兼容性更好。
小提示:如果部分用户的 shell 配置中存在大量自定义启动逻辑,担心影响脚本执行效率,可选择下面的方案2。
方案2:自动拼接source逻辑
如果你不想使用登录 shell 模式,也可以在 Java 层执行目标命令前,隐式拼接加载配置的逻辑,不需要用户修改脚本:
// 先加载bash_profile,丢弃source过程的输出,再执行目标命令 String wrappedShStr = "source ~/.bash_profile > /dev/null 2>&1; " + shStr; String[] command = new String[] {"bash","-c",wrappedShStr};
这个方案同样不需要硬编码 flutter 路径,能自动适配不同用户的配置。
内容的提问来源于stack exchange,提问作者Nullable

