You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java启动WinAppDriver操作Windows文件选择器时并发超时异常求助

Java/Eclipse下Appium+WinAppDriver并发超时问题

问题场景

手动从文件资源管理器启动WinAppDriver时,所有操作完全正常;但通过Java代码启动WinAppDriver后,执行文件选择器操作会触发并发超时异常导致程序中止。此时若在Eclipse中点击停止按钮,文件名却能正确输入到文件选择器中。怀疑是Java进程阻碍了WindowsDriver发送数据,求验证及解决方案。

依赖环境

  • selenium-java 4.5.0
  • java-client 8.1.1(升级到后续版本会出现ImmutableMap转Capabilities失败的错误)
  • 必须依赖Appium以配合Selenium Grid使用

相关代码

获取WinAppDriver的代码

public static WindowsDriver getDriver() {
    try {
        if (!checkForRunning()) {
            String executable = Properties.getProperty("test.winappdriver.location", winAppDriver);
            Runtime.getRuntime().exec(executable);
            Thread.sleep(10000);
        }
    } catch (Exception ex) {
        throw new AssertionError(ex.getMessage(), ex);
    }

    HttpCommandExecutor exec = null;

    try {
        exec = new HttpCommandExecutor(new URL("http://127.0.0.1:4723/"));
    } catch (MalformedURLException e) {
        throw new AssertionError(e.getMessage(), e);
    }

    DesiredCapabilities dcaps = new DesiredCapabilities();
    dcaps.setCapability("automationName", "Windows");
    dcaps.setCapability("app", "Root");
    dcaps.setCapability("platformName", "Windows");
    dcaps.setCapability("deviceName", "Windows PC");
    WindowsDriver app = new WindowsDriver(exec, dcaps);
    return app;
}

代码逻辑:检查WinAppDriver是否运行,未运行则启动并固定等待10秒。

操作Windows文件选择器的代码

List<WebElement> g = wdriver.findElements(By.name("File name:"));
if (g.size() < 2) {
            System.out.println("*** retry");
            g = wdriver.findElements(By.name("File name:"));
}
g.get(0).sendKeys(" ");
WebElement clickIt = g.get(1);
clickIt.click();
String curdir = System.getProperty("user.dir");
// add Keys.ENTER to file name to close it, since the OK button is hard to find
String f2 = StringUtils.join(curdir, "\"", fileName, Keys.ENTER);
clickIt.sendKeys(f2);

问题分析与解决办法

关于Java进程阻碍的验证

你的怀疑成立:Runtime.getRuntime().exec(executable)启动WinAppDriver后,子进程的标准输出/错误流如果未被消费,会导致缓冲区填满,进而阻塞子进程运行,间接打断WinAppDriver与Java客户端的通信链路,最终引发超时。手动启动时无此问题,是因为子进程输出流关联到系统控制台,不会被阻塞。

针对性解决方案

  1. 消费WinAppDriver进程的输出流
    修改启动逻辑,添加线程消费子进程的输出/错误流,避免缓冲区阻塞:

    Process winAppDriverProcess = Runtime.getRuntime().exec(executable);
    // 启动线程消费标准输出
    new Thread(() -> {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(winAppDriverProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("WinAppDriver Log: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();
    // 启动线程消费错误输出
    new Thread(() -> {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(winAppDriverProcess.getErrorStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.err.println("WinAppDriver Error: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();
    

    同时替换固定等待Thread.sleep(10000)为端口连通性轮询,更可靠地等待WinAppDriver启动完成:

    int port = 4723;
    long timeout = System.currentTimeMillis() + 15000;
    boolean isPortOpen = false;
    while (System.currentTimeMillis() < timeout && !isPortOpen) {
        try (Socket socket = new Socket("127.0.0.1", port)) {
            isPortOpen = true;
        } catch (IOException ignored) {
            Thread.sleep(1000);
        }
    }
    if (!isPortOpen) {
        throw new AssertionError("WinAppDriver failed to start within timeout");
    }
    
  2. 确保进程权限
    以管理员权限启动Eclipse(右键选择"Run as Administrator"),WinAppDriver需要管理员权限才能正常控制系统级窗口(如文件选择器),代码启动时会继承Java进程的权限,权限不足会导致通信异常。

  3. 优化文件选择器操作逻辑
    替换简单重试为显式等待,同时修正路径拼接逻辑:

    WebDriverWait wait = new WebDriverWait(wdriver, Duration.ofSeconds(10));
    List<WebElement> fileInputs = wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.name("File name:"), 1));
    WebElement inputField = fileInputs.get(1);
    inputField.clear();
    // 直接拼接路径,避免StringUtils.join的参数错误
    String fullPath = curdir + "\\" + fileName;
    inputField.sendKeys(fullPath + Keys.ENTER);
    
  4. 版本兼容性校验
    确保Selenium Grid版本与selenium-java 4.5.0完全匹配,Appium服务器版本(若使用)需兼容java-client 8.1.1,版本不匹配也会引发通信超时问题。

内容的提问来源于stack exchange,提问作者Tony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 18:20:02