Skip to content

特殊控件toast识别

特殊控件 Toast

简介

Toast 是一种轻量级的消息提示,常常以小弹框的形式出现,一般出现 1 到 2 秒会自动消失,可以出现在屏幕上中下任意位置。

Toast 具有如下的特点:

  • 无法被点击,不同于 Dialog,永远不会获得焦点。
  • Toast 显示的时间有限,Toast 会根据用户设置的显示时间后自动消失
  • 是系统级别的控件,属于系统 settings

Toast 的思想:尽可能不引人注意,同时还向用户显示信息,希望用户看到。

如下图,就是一种 Toast 消息框类型:

Toast 定位

Appium 在抓取 Toast 时,使用的是 uiautomator 底层,然后将 Toast 元素放入控件树中。需要注意的是,Toast 本身并不属于常规的用户界面控件,而是一种短暂的消息提示,在这个过程中,Appium 使用的是 uiautomator2

Toast 出现的时间一般比较短,可以通过等待或者打印页面元素的方式判断是否存在,并且通过 Xapth 或者 class name(在Androidclass name 相当于 组件的路径名称:android.widget.Toast) 的定位方式找到 Toast 元素。在页面结构中,Toast 元素大致如下所示:

<!-- 在这里可以看到Toast消息提示框的
class是android.widget.Toast,
且一个页面一般只有一个 -->
<android.widget.Toast
  index="1"
  package="com.android.settings"
  class="android.widget.Toast"
  text="Clicked popup menu item Search"
  displayed="true"
/>

示例

  • 使用 appium 官方 Demo apk: API DEMO 进行练习,apk 网盘地址
  • 进入试验toast页面:view-> make a popup
  • 配置 driver 的初始化和关闭 driver 的步骤。

Python 示例:

class TestToast:

  def setup_class(self):
      caps = {
          'platformName': 'android',
          'appium:appPackage': 'io.appium.android.apis',
          'appium:appActivity': 'io.appium.android.apis.view.PopupMenu1',
          "appium:noReset": True,
          "appium:shouldTerminateApp": True
      }
      self.driver = webdriver.Remote(
          "http://127.0.0.1:4723",
          options=UiAutomator2Options().load_capabilities(caps)
      )
      self.driver.implicitly_wait(15)

  def teardown_class(self):
      self.driver.quit()

Java 示例:

class TestToast {
    public static AndroidDriver driver;

    @BeforeAll
    public static void setUp() throws MalformedURLException {
        // 初始化capability
        DesiredCapabilities caps = new DesiredCapabilities();
        // 设置 app 安装的平台(Android、iOS)
        caps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
        // 设置 app 的包名
        caps.setCapability("appPackage", "io.appium.android.apis");
        // 设置 app 的启动页
        caps.setCapability("appActivity", "io.appium.android.apis.view.PopupMenu1");
        // 设置 app 不清空缓存
        caps.setCapability("appium:noReset", true);
        // 设置 app 不重启
        caps.setCapability("appium:shouldTerminateApp", true);

        URL remoteUrl = new URL("http://127.0.0.1:4723");
        driver = new AndroidDriver(remoteUrl, caps);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
    }

    @AfterAll
    public static void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}
  • 定位 toast 消息提示框

Python 示例:

class TestToast:

  def test_get_toast(self):
      # 定位到 Make a Popup! 按钮并点击
      self.driver.find_element(
          AppiumBy.ACCESSIBILITY_ID,
          "Make a Popup!"
      ).click()
      # 消息框类型选择search
      self.driver.find_element(
          AppiumBy.XPATH,
          "//*[@text='Search']"
      ).click()
      # 获取 Toast 弹框文本信息
      result = self.driver.find_element(
          AppiumBy.XPATH,
          "//*[contains(@text, 'Clicked popup')]"
      ).text
      assert result == "Clicked popup menu item Search"

Java 示例:

@Test
public void testGetToast() {
    // 定位到 Make a Popup! 按钮并点击
    WebElement buttonMakeAPopup = driver.findElement(AppiumBy.accessibilityId("Make a Popup!"));
    buttonMakeAPopup.click();
    // 消息框类型选择search
    WebElement checkbox = driver.findElement(AppiumBy.xpath("//*[@text='Search']"));
    checkbox.click();
    // 获取 Toast 弹框文本信息
    WebElement toastPopupEle = driver.findElement(AppiumBy.xpath("//*[contains(@text, 'Clicked popup')]"));
    String result = toastPopupEle.getText();
    assert result.equals("Clicked popup menu item Search");
}

总结

  • Toast 定位方法