使用Appium执行TouchActions操作时触发ClassCastException错误求助
解决Appium中
io.appium.java_client.AppiumDriver cannot be cast to org.openqa.selenium.interactions.HasTouchScreen异常 你的问题根源很清晰:你用了Selenium原生的TouchActions类来实现触摸操作,但这个类要求驱动必须实现HasTouchScreen接口,而AppiumDriver并没有实现这个接口,所以直接抛出了类型转换异常。
解决方案:使用Appium官方适配的触摸操作API
Appium Java客户端自带了专门的触摸操作工具类,完全适配AppiumDriver,不需要做任何类型转换。下面分两种场景给你修改代码:
1. 适用于Appium 1.x(或偏好旧API):使用io.appium.java_client.TouchAction
首先替换导入的包,把Selenium的TouchActions换成Appium专属的TouchAction:
// 删除这行Selenium的导入:import org.openqa.selenium.interactions.touch.TouchActions; import io.appium.java_client.TouchAction; import io.appium.java_client.touch.LongPressOptions; import io.appium.java_client.touch.offset.ElementOption; import io.appium.java_client.touch.offset.PointOption;
然后修改你的testSearchAppium方法中的触摸操作逻辑:
@Test public void testSearchAppium() throws Throwable { driver.get(AppURL); // 用WebDriverWait替代Thread.sleep,让测试更稳定 wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[@class='notnow']"))).click(); // 初始化Appium的TouchAction实例 TouchAction action = new TouchAction(driver); // 长按目标元素 action.longPress(LongPressOptions.longPressOptions() .withElement(ElementOption.element(driver.findElement(By.xpath("//a[@class='scroll__nav-link active-nav']"))))) .release() // 必须调用release结束长按动作 .perform(); Thread.sleep(3000); // 建议后续替换为WebDriverWait等待操作反馈 // 模拟向右滑动20像素(x轴偏移+20,y轴保持不变) // 坐标可以根据实际元素位置动态计算,这里用固定值做示例 action.press(PointOption.point(100, 500)) .waitAction() .moveTo(PointOption.point(120, 500)) .release() .perform(); }
2. 适用于Appium 2.x+:推荐使用W3C标准的PointerInput和Sequence
TouchAction在新版本Appium中已被标记为Deprecated,官方推荐使用W3C标准API实现触摸操作,兼容性更好:
// 导入需要的包 import org.openqa.selenium.interactions.PointerInput; import org.openqa.selenium.interactions.Sequence; import java.time.Duration; import java.util.Collections; @Test public void testSearchAppium() throws Throwable { driver.get(AppURL); wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[@class='notnow']"))).click(); PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger"); WebElement target = driver.findElement(By.xpath("//a[@class='scroll__nav-link active-nav']")); // 计算元素中心坐标,避免点击到元素边缘 int centerX = target.getLocation().getX() + target.getSize().getWidth() / 2; int centerY = target.getLocation().getY() + target.getSize().getHeight() / 2; // 实现长按操作(保持2秒) Sequence longPress = new Sequence(finger, 1); longPress.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY)); longPress.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg())); longPress.addAction(finger.createPointerMove(Duration.ofSeconds(2), PointerInput.Origin.viewport(), centerX, centerY)); longPress.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Collections.singletonList(longPress)); Thread.sleep(3000); // 实现向右滑动20像素的操作 Sequence flick = new Sequence(finger, 2); flick.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY)); flick.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg())); flick.addAction(finger.createPointerMove(Duration.ofMillis(300), PointerInput.Origin.viewport(), centerX + 20, centerY)); flick.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Collections.singletonList(flick)); }
额外优化建议
- 尽量减少
Thread.sleep()的使用,改用WebDriverWait等待元素状态变化,提升测试稳定性 - 确保Appium Java客户端版本与Appium Server版本兼容,版本不匹配容易引发各类异常
- 滑动操作的坐标尽量基于元素位置动态计算,避免写死固定值,适配不同尺寸的移动设备
内容的提问来源于stack exchange,提问作者Madan
相关产品推荐
相关产品推荐

