uiautomator2学习2——uiautomator2的Device
uiautomator2的介绍
前面有提到过安装weditor的同时也会下载其依赖包,其中包括uiautomator2,
因为weditor的代码就是用的uiautomator2的那一套。
上一篇文章讲到了weditor,可能会有同学问,代码那个d是什么?答案很简单,你点击一下按个“重置代码”按钮你就会看到了d是怎么来的。
注意一下:一旦重置代码后,要把“import uiautomator2 as”、“d = u2.connect()” 这两行去掉,不然你进行运行整个代码的时候会出错。
有些同学会发现,在weditor的代码部分会发现你录制的脚本里面,有些代码是d.开头的,有些是d(resourceId=“xxxx”).开头,d具体又是什么呢?d和 d(resourceId=“xxxx”) 是不是一样的?而这就是我要继续讲的内容。
d 和 d(resourceId=“xxxx”)
d 的来源
刚刚提到的“d = u2.connect()”
d具体是什么,我们可以去看下uiautomator2的源码
def connect(addr=None) -> Device:
"""
Args:
addr (str): uiautomator server address or serial number. default from env-var ANDROID_DEVICE_IP
Returns:
Device
Raises:
ConnectError
Example:
connect("10.0.0.1:7912")
connect("10.0.0.1") # use default 7912 port
connect("http://10.0.0.1")
connect("http://10.0.0.1:7912")
connect("cff1123ea") # adb device serial number
"""
if not addr or addr == '+':
addr = os.getenv('ANDROID_DEVICE_IP') or os.getenv("ANDROID_SERIAL")
wifi_addr = _fix_wifi_addr(addr)
if wifi_addr:
return connect_wifi(addr)
return connect_usb(addr)
def connect_adb_wifi(addr) -> Device:
"""
Run adb connect, and then call connect_usb(..)
Args:
addr: ip+port which can be used for "adb connect" argument
Raises:
ConnectError
"""
assert isinstance(addr, six.string_types)
subprocess.call([adbutils.adb_path(), "connect", addr])
try:
subprocess.call([adbutils.adb_path(), "-s", addr, "wait-for-device"],
timeout=2)
except subprocess.TimeoutExpired:
raise ConnectError("Fail execute", "adb connect " + addr)
return connect_usb(addr)
def connect_usb(serial: Optional[str] = None, init: bool = False) -> Device:
"""
Args:
serial (str): android device serial
Returns:
Device
Raises:
ConnectError
"""
if init:
logger.warning("connect_usb, args init=True is deprecated since 2.8.0")
if not serial:
device = adbutils.adb.device()
serial = device.serial
return Device(serial)
def connect_wifi(addr: str) -> Device:
"""
Args:
addr (str) uiautomator server address.
Returns:
Device
Raises:
ConnectError
Examples:
connect_wifi("10.0.0.1")
"""
_addr = _fix_wifi_addr(addr)
if _addr is None:
raise ConnectError("addr is invalid or atx-agent is not running", addr)
del addr
return Device(_addr)
源码内容很多,我大致的说一下原理,就不一行行代码的解释了。
connect 方法会根据具体情况去调用 connect_usb 方法或者 connect_wifi 方法,这 connect_usb 和connect_wifi 这两个方法最终都是返回 Device 实例。
注意:connect 和 connect_usb、connect_wifi 都不是Device的方法,别弄混了。
Device的类是什么?
源码是这样的
class Device(_Device, _AppMixIn, _PluginMixIn, _InputMethodMixIn, _DeprecatedMixIn):
""" Device object """
Device继承了_Device、_AppMixIn、_PluginMixIn、_InputMethodMixIn、_DeprecatedMixIn这几个类。没有去覆写其父类的方法。
结合上面的提到的内容,我们现在知道了d其实就是Device的实例。
d(resourceId=“xxxx”) 的来源
现在知道了 d 是什么了,那 d(resourceId=“xxxx”) 是不是也一样呢?
答案是不一样,继续往下看。
d(resourceId=“xxxx”) 其实是Device实例调用了它的父类_Device的__call__方法,源码如下:
class _Device(_BaseClient):
......
def __call__(self, **kwargs):
return UiObject(self, Selector(**kwargs))
关于__call__方法可以自己去百度一下,这里就不细讲了
通过查看源码,_Device的__call__方法返回的是UiObject实例。
因此可知weditor的 d 是Device实例,而 d(resourceId=“xxxx”) 是 UiObject实例。
uiautomator2的connect方法
# 连接设备。
# 源码:
connect(addr=None) -> Device
# 参数:
# addr:可以为IP,也可以为设备码(序列号)。
# 返回:Device 类型实例。
# 示例:
d = connect("10.0.0.1:7912")
d = connect("10.0.0.1") # 默认使用端口7912
d = connect("http://10.0.0.1")
d = connect("http://10.0.0.1:7912")
d = connect("cff1123ea") # adb 设备序列号
后续会说明 Device 和 UiObject 的方法。