因为工作需要,使用到UIAutomator2中watcher(观察者)的功能,在官方文档查阅后,觉得对我个人来说有些不够直接,所以在本地尝试的基础上,将watcher的功能进行介绍如下,如若存在纰漏请您指出。【文末附有Watcher的官方文档】

* 本篇文章整理的时候基于uiautomator2 0.3.3,现在已经是2.0.0了,不过功能应当还是适配的,阅读时请尽可能参考官方文档

* 2020.04.13 uiautomator2最新文档里面,watchers已经都替换为watcher了,使用时请注意,以下内容为保持一致性,暂不修改

一、watcher是什么

与大多语言一样,watcher是一个观察者,它可以检测到设备页面中的变化,比如某个文本/描述/类名等的出现或者改变,然后进行下一步的点击/按钮操作

二、watcher怎么用

Step.1 注册一个watcher

d.watcher("WATCHER_NAME").when(text="确认").click(text="确认")
# Same as
d.watcher("ALERT").when(text="OK").click()

这句话表示:注册一个名字为“WATCHER_NAME”的watcher,当存在UiSelector满足“text='确认'”的时候,执行点击操作

d.watcher("WATCHER_NAME2").when(text="OK").when(text="Wait").press("back", "home")

下面这句则表示:注册一个名字为“WATCHER_NAME2”的watcher,当满足两个条件时,依次按back与home键

 

Step.2 watcher注册了,并不代表已经生效,需要手动开启它

开启方法(1)

# enable auto trigger watchers
d.watchers.watched = True

  使用这种方法,则会启动所有的观察者,并一直运行在手机后台,在你不想使用它的时候,需要使用d.watchers.watched = False手动关闭;当然,你也可以使用下方的remove方法移除某个watcher,如此它便不会再生效

开启方法(2)

# force to run all registered watchers
d.watchers.run()

  使用d.watchers.run(),则与方法(1)不同,它是在这条命令执行的瞬时启动一次,结束后便不会再触发

 

其他功能

1. 查看当前所有watcher(当然要搭配print使用啦)

d.watchers
# a list of all registered watchers

2. 从已注册的watchers移除某个/全部观察者

# remove the named watcher
d.watcher("watcher_name").remove()

# or this way
d.watchers.remove("watcher_name")

# remove all registered watchers
d.watchers.remove()

3. 判断 某个/所有观察者中的某个 是否已经被触发过

d.watcher("watcher_name").triggered
# true in case of the specified watcher triggered, else false

d.watchers.triggered
#  true in case of any watcher triggered

如果一个watcher被触发过,这个信息经过我本地测试 应当也是被存储在手机后台的,你需要使用d.watchers.reset()来重置

# reset all triggered watchers, after that, d.watchers.triggered will be false.
d.watchers.reset()

 

三、watcher使用案例

watcher的设计思路主要是为了解决一些 弹窗 或者 确认框 问题,比如需要点击“确定”、“下一步”、“允许”等,这里我以 手机自动挂断功能 为例来展示watcher的简单使用:

(1)如果是使用d.watchers.watched = True,那么你可以先执行脚本结束后再进行呼叫,来测试watcher是不是运行在手机后台

import uiautomator2 as u2


# 连接被叫设备
d = u2.connect('******')

# 注册一个名字为"DECLINE"的watcher,当存在UiSelector的description="拒绝"时,点击
d.watcher("DECLINE").when(description="拒绝").click()

# 查看DECLINE是否已经 注册 且 触发过
print("Triggered 1:", d.watcher("DECLINE").triggered)

# 启动方法1:后台启动,持续监控
d.watchers.watched = True
# d.watchers.watched = False

# 启动方法2:瞬时启动
# d.watchers.run()


# 查看DECLINE是否已经 注册 且 触发过
print("Triggered 2:", d.watcher("DECLINE").triggered)

# 重置watchers的triggered状态
d.watchers.reset()

# 重置后,查看DECLINE是否已经 注册 且 触发过
print("Triggered 3:", d.watcher("DECLINE").triggered)


# 查看当前已经注册的watchers
print("Watchers 1:", d.watchers)

# 移除DECLINE这个watcher
# d.watcher("DECLINE").remove()

# 移除后,查看当前已经注册的watchers
# print("Watchers 2:", d.watchers)

首先运行脚本后结果如下:

python uiautomator python uiautomator2 watcher 原理_python uiautomator

然后我们进行拨打电话,会发现被叫主动拒接电话。

之后,我们再次运行脚本,可以看到,因为刚才成功触发了watcher,triggered变为了True:

python uiautomator python uiautomator2 watcher 原理_自动化测试_02

另外,如果你想要这个watcher失效,需要手动触发d.watchers.watched=False,或者移除d.watcher("DECLINE").remove()

(2)如果是使用d.watchers.run(),则需要在电话已经处于呼叫的过程中触发脚本

import uiautomator2 as u2


# 连接被叫设备
d = u2.connect('******')

# 注册一个名字为"DECLINE"的watcher,当存在UiSelector的description="拒绝"时,点击
d.watcher("DECLINE").when(description="拒绝").click()

# 查看DECLINE是否已经 注册 且 触发过
print("Triggered 1:", d.watcher("DECLINE").triggered)

# 启动方法1:后台启动,持续监控
# d.watchers.watched = True
# d.watchers.watched = False

# 启动方法2:瞬时启动
d.watchers.run()


# 查看DECLINE是否已经 注册 且 触发过
print("Triggered 2:", d.watcher("DECLINE").triggered)

# 重置watchers的triggered状态
d.watchers.reset()

# 重置后,查看DECLINE是否已经 注册 且 触发过
print("Triggered 3:", d.watcher("DECLINE").triggered)


# 查看当前已经注册的watchers
print("Watchers 1:", d.watchers)

# 移除DECLINE这个watcher
d.watcher("DECLINE").remove()

# 移除后,查看当前已经注册的watchers
print("Watchers 2:", d.watchers)

对于上面这份代码(),直接运行后的结果为:

python uiautomator python uiautomator2 watcher 原理_python_03

而如果在进行电话呼叫时,运行脚本的结果如下。另外,在脚本运行的时刻,成功拒接电话

python uiautomator python uiautomator2 watcher 原理_watcher_04

 

================================================================

Watcher官方文档内容如下:(源自:https://github.com/openatx/uiautomator2

Watcher

You can register watchers to perform some actions when a selector does not find a match.

  • Register Watcher
    When a selector can not find a match, uiautomator2 will run all registered watchers.
  • Click target when conditions match
d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .click(text="Force Close")
# d.watcher(name) ## creates a new named watcher.
#  .when(condition)  ## the UiSelector condition of the watcher.
#  .click(target)  ## perform click action on the target UiSelector.

There is also a trick about click. You can use click without arguments.

d.watcher("ALERT").when(text="OK").click()
# Same as
d.watcher("ALERT").when(text="OK").click(text="OK")
  • Press key when a condition becomes true
d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .press("back", "home")
# d.watcher(name) ## creates a new named watcher.
#  .when(condition)  ## the UiSelector condition of the watcher.
#  .press(<keyname>, ..., <keyname>.()  ## press keys one by one in sequence.
  • Check if the named watcher triggered
    A watcher is triggered, which means the watcher was run and all its conditions matched.
d.watcher("watcher_name").triggered
# true in case of the specified watcher triggered, else false
  • Remove a named watcher
# remove the watcher
d.watcher("watcher_name").remove()
  • List all watchers
d.watchers
# a list of all registered watchers
  • Check for any triggered watcher
d.watchers.triggered
#  true in case of any watcher triggered
  • Reset all triggered watchers
# reset all triggered watchers, after that, d.watchers.triggered will be false.
d.watchers.reset()
  • Remove watchers
# remove all registered watchers
d.watchers.remove()
# remove the named watcher, same as d.watcher("watcher_name").remove()
d.watchers.remove("watcher_name")
  • Force to run all watchers
# force to run all registered watchers
d.watchers.run()
  • Run all watchers when page update.
    通常可以用来自动点击权限确认框,或者自动安装
d.watcher("OK").when(text="OK").click(text="OK")
# enable auto trigger watchers
d.watchers.watched = True

# disable auto trigger watchers
d.watchers.watched = False

# get current trigger watchers status
assert d.watchers.watched == False