环境

  1. APPIUM version: 1.6.3
  2. uiautomator 2.0
  3. java8
  4. java-client meta6

测试步骤

用例 1

  1. 打开 APP 的内嵌 H5 页面并切换到 webview
  2. 执行控件点击:element.click();

测试结果

用例 1

  1. 控件点击成功了,但是界面没有反应,开启了指针位置,发现点在了别处

问题分析

  1. 从结果来看,这个控件是找到了的,但是坐标值不正确
  2. 在切换到 webview 之后,通过获取获取根节点 xpath://*[1] 的 size 信息,得到 360x570,而控件位置是 313,21,但实际屏幕上的位置应该是:990x303
  3. 应该是按比例缩放的,所以我又获取了手机屏幕的 size:1080x1920,计算之后发现横坐标是对的,但是纵坐标还是不对,导致我有点怀疑,难道不是按比例缩放的?
  4. 在写本贴想求助的时候,突然想到它是在 webview 的框子里面的,所以不能通过屏幕 size 来计算它的坐标值,切到 native_app 后,获取 webview 这个框子的 size:1080x1710

结果

  1. 切到 H5 context
  2. 获取控件坐标值以及根节点的宽和高
  3. 切回 native 获取 webview 框的宽和高和起始位置
  4. 计算 native 中 H5 控件的坐标值:nativeStartX+elementX*nativeWebviewWidth/rootElementWidth,nativeStartY+elementY*nativeWebviewHeight/rootElementHeight

代码

String context = driver.getContext();
if (context.startsWith("NATIVE")) {
    driver.findElementByXPath(locator).click();
} else {
    WebElement rootElement = driver.findElementByXPath("//*[1]");
    int rootElementWidth = rootElement.getSize().width;
    int rootElementHeight = rootElement.getSize().height;

    WebElement element = driver.findElementByXPath("the xpath of you want to click");
    Dimension elementSize = element.getSize();
    Point elementPoint = element.getLocation();
    int centerX = elementPoint.x + elementSize.width/2+1;
    int centerY = elementPoint.y + elementSize.height/2+1;

    driver.context("NATIVE_APP");
    WebElement webviewElement = driver.findElementByXPath("//*[@class='android.webkit.WebView']");
    Dimension webviewSize = webviewElement.getSize();
    Point webviewPoint = webviewElement.getLocation();
    int webviewWidth = webviewSize.width;
    int webviewHeight = webviewSize.height;
    int startX = webviewPoint.x;
    int startY = webviewPoint.y;

    logger.info("web size:" + rootElementWidth + "x"+ rootElementHeight);
    logger.info("native webview size:" + webviewWidth + "x" + webviewHeight);
    logger.info("element location:" + centerX + "x" + centerY);
    logger.info("click:" + (startX + centerX*webviewWidth/rootElementWidth) + "x"
            + (startY + centerY*webviewHeight/rootElementHeight));

    TouchAction t = new TouchAction(driver);
    t.press(startX + centerX*webviewWidth/rootElementWidth, startY + centerY*webviewHeight/rootElementHeight).release().perform();
    Set<String> contextNames = driver.getContextHandles();
    for (String contextName : contextNames) {
        if (contextName.startsWith("WEB")){
            driver.context(contextName);
        }
    }
}

感慨

本来是发求助贴的,结果写到一半灵光一闪,找到问题解决方案了,
所以发贴还是有大大用处的,至少可以帮助自己梳理一下问题
另外还踩坑了,尝试在 webview 界面点击超出 webview 屏幕之外的坐标位置时,
appium 报的错误居然是未实现,一直以为是我的点击坐标的方法不正确导致的,
害我尝试了好多次才领悟到可能是超过了范围导致的。

Caused by: org.openqa.selenium.WebDriverException: Method has not yet been implemented (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 17 milliseconds
Build info: version: '3.4.0', revision: 'unknown', time: 'unknown'
System info: host: 'CNHQ-16071101N', ip: '10.24.42.87', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.8.0_101'
Driver info: io.appium.java_client.android.AndroidDriver
Capabilities [{appPackage=com.suning.mobile.epa, appActivity=com.suning.mobile.epa.ui.init.SplashActivity, noReset=true, noSign=true, autoLaunch=true, newCommandTimeout=600, automationName=UIAutomator2, javascriptEnabled=true, platformName=Android, deviceName=android, platform=ANY}]
Session ID: a1d21255-31e8-42f6-8905-6debf666b706
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:215)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:167)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:671)
    at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
    at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
    at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
    at io.appium.java_client.PerformsTouchActions.performTouchAction(PerformsTouchActions.java:39)
    at io.appium.java_client.TouchAction.perform(TouchAction.java:381)
    at cn.suning.automation.keyword.MobileElementKeyword.elementClick(MobileElementKeyword.java:229)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at cn.suning.automation.execute.KeywordExecuter.run(KeywordExecuter.java:94)

对比一年前的控件 + 偏移量的方法,还是有进步的。


↙↙↙阅读原文可查看相关链接,并与作者交流