我们公司的 app 是需要登录的, 之前 capabilities.setCapability("automationName", "Appium");的时候一切都好.

为了捕获 toast 消息, 使用了 capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);(参考 carl 的文章https://testerhome.com/topics/8335), 现在的问题是可以捕获 toast 消息,但是却无法登录. 每次一输入密码就报空指针异常. (输入密码行就是被注释的那行)

环境:
APPIUM Version: 1.7.1
JAVA Client: 5.0.4
JAVA: 1.8
UiAutomator2 Drvier(版本未知, 不知道咋看)

代码如下:

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

public class Test3 {

    private AndroidDriver driver = null;
    private int sleepInterval = 15;
    private Log log = LogFactory.getLog(this.getClass().getName());

    @Before
    public void setUp() throws MalformedURLException {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("deviceName", "Andorid Emulator");
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
        capabilities.setCapability("platformName", "Android");
        capabilities.setCapability("platformVersion", "4.4.2");
        capabilities.setCapability("appPackage", "com.testgroup.testdoctor");
        capabilities.setCapability("appActivity", ".user.UserLoginActivity");
        capabilities.setCapability("newCommandTimeout", 0);
//        capabilities.setCapability("unicodeKeyboard", true);
//        capabilities.setCapability("resetKeyboard", true);

        URL url = new URL("http://127.0.0.1:4723/wd/hub");
        driver = new AndroidDriver(url, capabilities);
        driver.manage().timeouts().implicitlyWait(sleepInterval, TimeUnit.SECONDS);
    }

    @After
    public void tearDown() {
        driver.quit();
    }

    @Test
    public void logonTest() throws InterruptedException, MalformedURLException {

        // 登录页面
        driver.findElement(By.id("com.testgroup.testdoctor:id/username")).sendKeys("13439155766");
        driver.findElement(By.id("com.testgroup.testdoctor:id/pwd")).click();
//        driver.findElement(By.id("com.testgroup.testdoctor:id/pwd")).sendKeys("88888");
        driver.findElement(By.id("com.testgroup.testdoctor:id/login")).click();
        String toast = "请输入密码";
        try {
            final WebDriverWait wait = new WebDriverWait(driver, 3);
            Assert.assertNotNull(wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//*[contains(@text,'" + toast + "')]"))));
            log.info("查找toast成功!");

        } catch (Exception e) {
            throw new AssertionError("找不到" + toast);
        }


    }


}

Appium 日志:

[HTTP] --> POST /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d/element {"using":"id","value":"com.testgroup.testdoctor:id/pwd"}
[MJSONWP] Calling AppiumDriver.findElement() with args: ["id","com.testgroup.testdoctor:id/pwd","c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
[BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
[BaseDriver] Waiting up to 15000 ms for condition
[JSONWP Proxy] Proxying [POST /element] to [POST http://localhost:8200/wd/hub/session/c458c76b-f5f4-41ec-88f6-772f80f4b201/element] with body: {"strategy":"id","selector":"com.testgroup.testdoctor:id/pwd","context":"","multiple":false}
[JSONWP Proxy] Got response with status 200: {"value":{"ELEMENT":"34389e1c-ae3e-44d5-8766-516d191f9c94"},"status":0,"sessionId":"c458c76b-f5f4-41ec-88f6-772f80f4b201"}
[MJSONWP] Responding to client with driver.findElement() result: {"ELEMENT":"34389e1c-ae3e-44d5-8766-516d191f9c94"}
[HTTP] <-- POST /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d/element 200 506 ms - 122 
[HTTP] --> GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d {}
[MJSONWP] Calling AppiumDriver.getSession() with args: ["c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[MJSONWP] Responding to client with driver.getSession() result: {"platform":"LINUX","webStorageEnabled":false,"takesScreenshot":true,"javascriptEnabled":true,"databaseEnabled":false,"networkConnectionEnabled":true,"locationContextEnabled":false,"warnings":{},"desired":{"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"Andorid Emulator"},"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"7N2XEE157U020698","deviceUDID":"7N2XEE157U020698","deviceScreenSize":"720x1280","deviceModel":"CHM-TL00H","deviceManufacturer":"HUAWEI"}
[HTTP] <-- GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d 200 1 ms - 833 
[HTTP] --> GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d {}
[MJSONWP] Calling AppiumDriver.getSession() with args: ["c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[MJSONWP] Responding to client with driver.getSession() result: {"platform":"LINUX","webStorageEnabled":false,"takesScreenshot":true,"javascriptEnabled":true,"databaseEnabled":false,"networkConnectionEnabled":true,"locationContextEnabled":false,"warnings":{},"desired":{"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"Andorid Emulator"},"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"7N2XEE157U020698","deviceUDID":"7N2XEE157U020698","deviceScreenSize":"720x1280","deviceModel":"CHM-TL00H","deviceManufacturer":"HUAWEI"}
[HTTP] <-- GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d 200 1 ms - 833 
[HTTP] --> GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d {}
[MJSONWP] Calling AppiumDriver.getSession() with args: ["c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[MJSONWP] Responding to client with driver.getSession() result: {"platform":"LINUX","webStorageEnabled":false,"takesScreenshot":true,"javascriptEnabled":true,"databaseEnabled":false,"networkConnectionEnabled":true,"locationContextEnabled":false,"warnings":{},"desired":{"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"Andorid Emulator"},"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"7N2XEE157U020698","deviceUDID":"7N2XEE157U020698","deviceScreenSize":"720x1280","deviceModel":"CHM-TL00H","deviceManufacturer":"HUAWEI"}
[HTTP] <-- GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d 200 1 ms - 833 
[HTTP] --> GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d {}
[MJSONWP] Calling AppiumDriver.getSession() with args: ["c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[MJSONWP] Responding to client with driver.getSession() result: {"platform":"LINUX","webStorageEnabled":false,"takesScreenshot":true,"javascriptEnabled":true,"databaseEnabled":false,"networkConnectionEnabled":true,"locationContextEnabled":false,"warnings":{},"desired":{"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"Andorid Emulator"},"appPackage":"com.testgroup.testdoctor","appActivity":".user.UserLoginActivity","newCommandTimeout":0,"platformVersion":"4.4.2","automationName":"UIAutomator2","platformName":"Android","deviceName":"7N2XEE157U020698","deviceUDID":"7N2XEE157U020698","deviceScreenSize":"720x1280","deviceModel":"CHM-TL00H","deviceManufacturer":"HUAWEI"}
[HTTP] <-- GET /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d 200 1 ms - 833 
[HTTP] --> POST /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d/element/34389e1c-ae3e-44d5-8766-516d191f9c94/value {"id":"34389e1c-ae3e-44d5-8766-516d191f9c94","value":["88888"]}
[MJSONWP] Calling AppiumDriver.setValue() with args: [["88888"],"34389e1c-ae3e-44d5-8766-516d191f9c94","c85a1b8a-1b32-44fe-92da-ab06913dfa5d"]
[JSONWP Proxy] Proxying [POST /element/34389e1c-ae3e-44d5-8766-516d191f9c94/value] to [POST http://localhost:8200/wd/hub/session/c458c76b-f5f4-41ec-88f6-772f80f4b201/element/34389e1c-ae3e-44d5-8766-516d191f9c94/value] with body: {"elementId":"34389e1c-ae3e-44d5-8766-516d191f9c94","text":"88888","replace":false}
[MJSONWP] Encountered internal error running command:  {"jsonwp":{"value":"java.lang.NullPointerException\n\tat android.support.test.uiautomator.UiObject2.setText(UiObject2.java:601)\n\tat io.appium.uiautomator2.model.UiObject2Element.setText(UiObject2Element.java:129)\n\tat io.appium.uiautomator2.handler.SendKeysToElement.safeHandle(SendKeysToElement.java:83)\n\tat io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:56)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:202)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:193)\n\tat io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:44)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)\n\tat io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)\n\tat io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)\n\tat io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)\n\tat io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:514)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:468)\n\tat io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)\n\tat io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)\n\tat io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)\n\tat java.lang.Thread.run(Thread.java:841)\n","status":13,"sessionId":"c458c76b-f5f4-41ec-88f6-772f80f4b201"}} ProxyRequestError: Could not proxy command to remote server. Original error: 500 - {"value":"java.lang.NullPointerException\n\tat android.support.test.uiautomator.UiObject2.setText(UiObject2.java:601)\n\tat io.appium.uiautomator2.model.UiObject2Element.setText(UiObject2Element.java:129)\n\tat io.appium.uiautomator2.handler.SendKeysToElement.safeHandle(SendKeysToElement.java:83)\n\tat io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:56)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:202)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:193)\n\tat io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:44)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)\n\tat io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)\n\tat io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)\n\tat io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)\n\tat io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)\n\tat io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:514)\n\tat io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:468)\n\tat io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)\n\tat io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)\n\tat io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)\n\tat java.lang.Thread.run(Thread.java:841)\n","status":13,"sessionId":"c458c76b-f5f4-41ec-88f6-772f80f4b201"}
    at JWProxy.proxy$ (C:\Users\tomavis\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\appium-base-driver\lib\jsonwp-proxy\proxy.js:152:13)
    at tryCatch (C:\Users\tomavis\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:67:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\tomavis\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:315:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as throw] (C:\Users\tomavis\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:100:21)
    at GeneratorFunctionPrototype.invoke (C:\Users\tomavis\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:136:37)
[HTTP] <-- POST /wd/hub/session/c85a1b8a-1b32-44fe-92da-ab06913dfa5d/element/34389e1c-ae3e-44d5-8766-516d191f9c94/value 500 38 ms - 3444 

最后的解决办法是修改登录方法, 根据 automationName 的值修改 i 登录方法:

public void logonAsUser(String username, String password)throws IOException{
        input_username_field(username);
        if(driver.getCapabilities().getCapability("automationName").equals(AutomationName.ANDROID_UIAUTOMATOR2)){
            password_field.click();
            Runtime.getRuntime().exec("cmd /c adb shell input keyboard text "+ password);
        }else {
            input_password_field(password);
        }
        tap_login_button();
    }

现在可以登录成功了, 但是很快, 其他需要输入文本的地方又报错了.


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