ATX ATX-uiautomator2 实现 webview 的操作

linpengcheng · 2018年03月29日 · 最后由 回复于 2023年04月10日 · 15721 次阅读

opeatx 的 uiautomator2 可以实现在不连接数据线的环境下实现 UI 自动化,但是好像对 app 内的 webview 还没有很好得支持。
在论坛里搜相关的帖子发现@codeskyblue 在 atx 项目中已经实现了对 Android Webview 的支持
https://testerhome.com/topics/7232

看了看源码,发现用 uiautomator2 应该也是可以来操作 Webview 的
把实践的步骤写出来供大家参考:
uiautomator2 的安装及配置就不介绍了可以看之前论坛的帖子:
https://testerhome.com/topics/12521
https://testerhome.com/topics/11357

下面是具体的操作步骤

1、环境安装及准备

chromedriver 的选择及安装

通过访问 chrome://inspect 安卓手机连接到电脑,可以查到当前 App 使用的 WebView 版本

https://npm.taobao.org/mirrors/chromedriver
下载对应版本的 chromedriver 到本地,并添加到 PATH 中。

不同版本对应的 chromedriver 的版本可以在这里看到
https://npm.taobao.org/mirrors/chromedriver/2.37/notes.txt

下载正确的 chromedriver 版本就好了

安装 selenium

手动安装额外的依赖库
pip install selenium

2、下载 chromedriver.py 并修改相关代码

https://github.com/NetEaseGame/ATX/blob/master/atx/ext/chromedriver.py
将代码复制到本地,也保存为chromedriver.py,并对相关的代码进行修改

只要改这 5 行就可以了

3、使用

用 macac 的 demo 演示的 apk 来测试一下看看,apk 下载地址:
https://npmcdn.com/android-app-bootstrap@latest/android_app_bootstrap/build/outputs/apk/android_app_bootstrap-debug.apk

在手机有线连接电脑的情况下,执行以下代码

import time
import uiautomator2 as u2
from chromedriver import ChromeDriver   #将chromedriver.py和该脚本放在同一目录下

d = u2.connect()
d.app_start('com.github.android_app_bootstrap')
d(text='Login').click()
d(text='Baidu').click()
time.sleep(3)
driver = ChromeDriver(d).driver()
driver.find_element_by_id('index-kw').click()
driver.find_element_by_id('index-kw').send_keys('Python')
driver.find_element_by_id('index-bn').click()
driver.quit()

在手机连接在电脑的情况下,上述的代码可以直接跑成功了,说明使用 uiautomator2 也是可以对 Webview 实现操作的嘛。
不过有个问题,selenium 调用的时候是要获取 devices 的。连线的时候d.serial可以直接获取到,但是数据线断了的时候怎么办呢?
这时候,chromedriver.py中增加的devices_ip这个就有用了,具体操作看下面。

4、手机 adb tcpip 实现 adb 无线连接

由于 chromedriver.py 的使用需要用到 adb 要想在手机不连接电脑的情况下,实现操作还需要对手机进行操作
操作步骤:

  1. 将 Android 设备与要运行 adb 的电脑连接到同一个局域网,比如连到同一个 WiFi。
  2. 将设备与电脑通过 USB 线连接。 应确保连接成功(可运行 adb devices 看是否能列出该设备)。
  3. 让设备在 5555 端口监听 TCP/IP 连接: adb tcpip 5555
  4. 断开 USB 连接。
  5. 找到设备的 IP 地址。 一般能在「设置」-「关于手机」-「状态信息」-「IP 地址」找到,uiautomator2 init之后安装的小汽车可以看到手机的 ip
  6. 通过 IP 地址连接设备。 adb connect <device-ip-address> 这里的 <device-ip-address> 就是上一步中找到的设备 IP 地址。
  7. 确认连接状态,在 USB 断开的状态下执行 adb devices 如果能看到 <device-ip-address>:5555 device 说明连接成功。

如果连接不了,请确认 Android 设备与电脑是连接到了同一个 WiFi,然后再次执行 adb connect <device-ip-address> 那一步;
如果还是不行的话,通过 adb kill-server 重新启动 adb 然后从头再来一次试试。

拔掉数据线 修改代码再来一次

确保在拔掉数据线后 执行adb devices能够发现设备<device-ip-address>:5555 device
修改代码,再次执行看看

import time
import uiautomator2 as u2
from chromedriver import ChromeDriver   #将chromedriver.py和该脚本放在同一目录下

d = u2.connect('10.33.103.214')  #手机的ip 为10.33.103.214
d.app_start('com.github.android_app_bootstrap')
d(text='Login').click()
d(text='Baidu').click()
time.sleep(3)
driver = ChromeDriver(d).driver(device_ip='10.33.103.214:5555') #增加device_ip参数
driver.find_element_by_id('index-kw').click()
driver.find_element_by_id('index-kw').send_keys('Python')
driver.find_element_by_id('index-bn').click()
driver.quit()

后面步骤的adb tcpip可以代码层面实现下,只是懒得去想了 先分享出来再说。。。。。

结果展示:

附言 1  ·  2018年07月10日

要自动化 webview,需要把被测 APP 的 webview 的 setWebContentsDebuggingEnabled 打开,需要开发人员支持,或者跑在模拟器上

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
最佳回复
Margaret 回复

先启动 webdriver 在 remote

共收到 63 条回复 时间 点赞

不错不错

请问运行这个 demo 的脚本时,总是在 driver = ChromeDriver(d).driver() 这一行报错何解?但设备一直在线的
后来我改用无线连接,然后报这个错,
请问你那用的是哪个版本的 chromedirver,我用了几个版本都不行

云敛晴空 回复

看看你手机 chrome://inspect 对应的 webview 的版本 然后去下载对应的就好了
我更新下帖子

linpengcheng 回复


这个是不是说明我的 chrome 版本是 v55,然后我是用了
2.25-2.28 四个版本的 chromedriver 版本,均是同一个问题

云敛晴空 回复

哪个问题? 把错误的日志放一下

linpengcheng 回复


提示我的设备不在线,但我的设备一直在线的,而且都是在那 driver = ChromeDriver(d).driver() 这一行时才报错,在这上面的代码都运行了,在手机端也是可以看到的

云敛晴空 回复

奇怪哦 u2 重新 init 下看看 adb devices 的结果是对的吗

linpengcheng 回复

重新 init 了,adb devices 结果也是对的,但就是一直报这个错,我如果只是运行 u2 跑纯 native 的 app 是没有问题,另外我的手机虽然跑 appium,但我把 appium 相关的都停止了,也是没用。。。。

云敛晴空 回复

那就不知道为什么了 换个手机就好了?

遇到了和 ancining 同样的问题,用同样的 chromedriver 版本 appium 切换 webview 都成功了,但是 u2 还是不行。而且把上面对应关系中的几个 chromedriver 版本都试过了,都是报同样的问题,怎么破呢。

云敛晴空 回复

请问你的问题解决了么。

回复

设备有没有连在电脑上?

linpengcheng 基于 ATX-Server 的 UI 自动化测试框架 中提及了此贴 06月18日 22:20


您好,请问这是什么原因呢?

JKzhishui 回复

右边的 37 行 括号里 加上个device_ip=None

linpengcheng 回复

谢谢大佬!可以了!

Java 可以使用吗?

Traceback (most recent call last):
File "C:/Users/Admin/Desktop/python-鱼/8.9/qu_tou_tiao.py", line 20, in
driver = ChromeDriver(d).driver(device_ip='192.168.0.20')
File "C:\Users\Admin\Desktop\python-鱼\8.9\chromedriver.py", line 58, in driver
dr = webdriver.Remote('http://localhost:%d' % self.port, capabilities)
File "D:\Python3.5.4\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 154, in __init
_
self.start_session(desired_capabilities, browser_profile)
File "D:\Python3.5.4\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 243, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "D:\Python3.5.4\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 312, in execute
self.error_handler.check_response(response)
File "D:\Python3.5.4\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 237, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Device 192.168.0.20 is not online
(Driver info: chromedriver=2.31.488763 (092de99f48a300323ecf8c2a4e2e7cab51de5ba8),platform=Windows NT 10.0.17134 x86_64)
谁解决了, 求教, 加 qq837497936 有偿

塔克米 回复

499563266 加群讨论吧 atx-uiautomator2 的

Traceback (most recent call last):
  File "C:/Users/Administrator/PycharmProjects/ATX/WebView.py", line 25, in <module>
    main()
  File "C:/Users/Administrator/PycharmProjects/ATX/WebView.py", line 17, in main
    driver = ChromeDriver(d).driver()
  File "D:\Anaconda3\lib\site-packages\atx\ext\chromedriver.py", line 59, in driver
    dr = webdriver.Remote('http://localhost:%d' % self._port, capabilities)
  File "D:\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 156, in __init__
    self.start_session(capabilities, browser_profile)
  File "D:\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 251, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "D:\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 320, in execute
    self.error_handler.check_response(response)
  File "D:\Anaconda3\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: unable to discover open pages
  (Driver info: chromedriver=2.29.461591 (62ebf098771772160f391d75e589dc567915b233),platform=Windows NT 10.0.17134 x86_64)

实例化 driver 的时候报错

回复

看看你的 chromeOptions 里的东西有么有填对 暂时也看不出来什么问题

linpengcheng 回复
app = self._d.current_app()
capabilities = {
    'chromeOptions': {
        'androidDeviceSerial': device_ip or self._d.serial,
        'androidPackage': package or app['package'],
        'androidUseRunningApp': attach,
        'androidProcess': process or app['package'],
        'androidActivity': activity or app['activity'],
    }
}

楼主有用 atx 测小程序的实践吗? 我主要卡在 原生和 webview 切换的部分

回复

没怎么试过😂

云敛晴空 回复

driver = ChromeDriver(d).driver(device_ip = "30.7.80.246:5555"), driver() 里没加 device_ip, 还是走的 serial

回复

有进展吗,可以切过去吗,我试了一下,会报错 selenium.common.exceptions.WebDriverException: Message: chrome not reachable

Jacc 回复

切不过去,报错差不多,感觉需要个上下文的过渡

codeskyblue Android WebView 研究笔记 中提及了此贴 08月29日 18:31
Jacc 回复

我也出现了这个问题,换多个手机,换 chromedriver 版本,运气好可能会遇到一个可以打开的

郝斯文 [该话题已被删除] 中提及了此贴 09月14日 11:18
xiaoquanzi 回复

把应用进程杀掉,重新来一波基本就 ok 了

楼主,操作 webview 你除了用这个 bootstrap,还有用过别的 app 吗?发现换了别的 debug 版本 app 根本就不行呀,定位了 bootstrap 里面的元素,发现都是原生的,虽然不知道是什么情况,感觉楼主的这个方法根本就实现不了 webview 的操作😂

zhunt 回复

操作 webview 其实就是调用 selenium 来实现的 ,webview 里操作用的都是 selenium 封装的方法
可能你 Chromedriver 启动配置有问题吧

linpengcheng 回复

chromedriver 启动配置就是用的楼主上面提到的那 5 行代码,跑 bootstrap 完全没问题,别的 app 就不行了,完全没有头绪,报错跟 21 楼一样 unable to discover open pages,所以才问楼主有试过别的 app 吗,别只能跑 bootstrap,网上资料又太少了😂

zhunt 回复

你别和我说你用的是微信

linpengcheng 回复

不是,我自己公司的 app,也是在 app 里面打开百度,然而并不能像在 bootstrap 里面那样操作,用 appium 是可以的,排除了是 app 的问题,然后就不知道是哪里出了问题

zhunt 回复

没在别的 APP 试过,也许是 chromedriver 版本的问题 。好久之前写的东西 我都忘记怎么操作了


请问,这个需要怎么解决?

yideng-dst 回复

你那个 chromedriver.py 的文件改对了没哦

yideng-dst 回复

11 行 最后 driver 括号里面的东西删掉再试一下


删掉就报这个错了

yideng-dst 回复

你的 chromedriver.py 文件没改好... def 那边没加上 device-ip 吧

linpengcheng 回复

可以了,感谢感谢

Traceback (most recent call last):
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connection.py", line 171, in _new_conn
(self._dns_host, self.port), self.timeout, **extra_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\util\connection.py", line 79, in create_connection
raise err
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\util\connection.py", line 69, in create_connection
sock.connect(sa)
ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
chunked=chunked)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 354, in _make_request
conn.request(method, url, **httplib_request_kw)
File "D:\Programs\Python\Python35\lib\http\client.py", line 1107, in request
self._send_request(method, url, body, headers)
File "D:\Programs\Python\Python35\lib\http\client.py", line 1152, in _send_request
self.endheaders(body)
File "D:\Programs\Python\Python35\lib\http\client.py", line 1103, in endheaders
self._send_output(message_body)
File "D:\Programs\Python\Python35\lib\http\client.py", line 934, in _send_output
self.send(msg)
File "D:\Programs\Python\Python35\lib\http\client.py", line 877, in send
self.connect()
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connection.py", line 196, in connect
conn = self._new_conn()
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connection.py", line 180, in _new_conn
self, "Failed to establish a new connection: %s" % e)
urllib3.exceptions.NewConnectionError: : Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "E:/PycharmProjects/mommonNewH5/LYnewH5/testCase/testMainTransfer.py", line 22, in setUp
self.driver = ChromeDriver(self.d).driver()
File "..\chromedriver.py", line 59, in driver
dr = webdriver.Remote('http://localhost:%d' % self.port, capabilities)
File "D:\Programs\Python\Python35\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 156, in __init
_
self.start_session(capabilities, browser_profile)
File "D:\Programs\Python\Python35\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 251, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "D:\Programs\Python\Python35\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 318, in execute
response = self.command_executor.execute(driver_command, params)
File "D:\Programs\Python\Python35\lib\site-packages\selenium\webdriver\remote\remote_connection.py", line 375, in execute
return self._request(command_info[0], url, body=data)
File "D:\Programs\Python\Python35\lib\site-packages\selenium\webdriver\remote\remote_connection.py", line 402, in _request
resp = http.request(method, url, body=body, headers=headers)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\request.py", line 72, in request
**urlopen_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\request.py", line 150, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\poolmanager.py", line 322, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 667, in urlopen
**response_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 667, in urlopen
**response_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 667, in urlopen
**response_kw)
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "D:\Programs\Python\Python35\lib\site-packages\urllib3\util\retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=9515): Max retries exceeded with url: /session (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。',))

这是什么情况?好像执行到 self.driver = ChromeDriver(self.d).driver() 就报错了

Margaret 回复

9515 被占用了?

linpengcheng 回复

刚查了端口号使用情况,没发现被占用~

Margaret 回复

那就不清楚了 你再调试看看 重新 init 一下

Margaret 回复

你这个问题解决了么,我也碰到了一样的问题

沈裕婷 回复

还没有,不知道问题出在哪~

Margaret 回复

你被测的 app 是调用 Android 自带的 webview 还是直接内置了腾讯的 x5 之类?

Margaret 回复

先启动 webdriver 在 remote

linpengcheng 回复

赞,感谢大佬提供的解决方法😀

Margaret 回复

由于目标计算机积极拒绝,无法连接。
这个是因为 chromedriver.exe 路径不对的问题,修改一下 chromedriver.py 中的路径,我也是刚刚弄好的 F:\chromedriver.exe,填写自己的 chromedriver.exe 路径
def _launch_webdriver(self):
print("start chromedriver instance")
p = subprocess.Popen(['F:\chromedriver.exe', '--port=' + str(self._port)])

finfou 回复

我这边即使加了 device_ip 还是连接不上,尝试过 5555 端口也不行

通过这个 chromedriver.py,无法实现 UC 的 webview。提示的错误是:selenium.common.exceptions.WebDriverException: Message: unknown error: Failed to get sockets matching:
通过 inspect 查到 UC 的版本是
WebView in com.UCMobile.dev (57.0.2987.108)
但是在运行,刚才的代码时,显示的是 (Driver info: chromedriver=71.0.3578.80 (2ac50e7249fbd55e6f517a28131605c9fb9fe897),platform=Mac OS X 10.14.2 x86_64)
是不是 ATX uiautomator2 实现 UC webview 是采用其他的方法呢?

请问,webview 切换后,唤起的页面是一片空白的是怎么回事呀?地址只是一个 data。

lgh75560 回复

修改 chromedriver 路径后会在 PC 端开启谷歌浏览器,请问是什么原因?

Mr.武 回复

你的脚本写的有些不正确的地方

请教一下,为什么按照您的提示,连上了 chromedriver,也打开了一个空白页面 ,但是什么都没有显示, chrome://inspect/#devices 里面倒是有显示 webview 的内容

请教下 我运行例子里面的代码,启动的怎么是 PC 端的 chrome 呢?

if name == 'main':
import uiautomator2 as u2
import time

d = u2.connect()
d.app_stop('com.github.android_app_bootstrap')
d.app_start('com.github.android_app_bootstrap')
d(text='Login').click()
d(text='Baidu').click()
time.sleep(3)
driver = ChromeDriver(d).driver()
driver.find_element_by_id('index-kw').click()
driver.find_element_by_id('index-kw').send_keys('Python')
driver.find_element_by_id('index-bn').click()
driver.quit()

Mr.武 回复

我这边也是遇到这个问题,启动的是 PC 端的浏览器。你的解决了吗?

qugo9955 回复

应该是脚本写法有问题 这个文档好久了 我有空看看还能不能正常跑通

linpengcheng 回复

这个问题怎么样了?我这边也遇到这个问题,有解决方案不?

uiautomator2, 拉起 ChromeDriver 报错,是否是 Chrome 兼容问题

[1645163734.564][SEVERE]: bind() returned an error: ͨ��ÿ���׽��ֵ�ַ(Э��/�����ַ/�˿�)ֻ����ʹ��һ�Ρ� (0x2740)
Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 9515
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
IPv6 port not available. Exiting...
[1645163734.596][SEVERE]: bind() returned an error: ͨ��ÿ���׽��ֵ�ַ(Э��/�����ַ/�˿�)ֻ����ʹ��һ�Ρ� (0x2740)
Traceback (most recent call last):
File "D:\Program Files\Python38\lib\site-packages\atx\ext\chromedriver.py", line 70, in driver
dr = webdriver.Remote('http://localhost:%d' % self.port, capabilities,options)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 268, in __init
_
self.start_session(capabilities, browser_profile)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 355, in start_session
capabilities.update({'firefox_profile': browser_profile.encoded})
AttributeError: 'Options' object has no attribute 'encoded'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "E:/APP/SmartMonkeyTest/uitest/android_uiparser_uiautomator.py", line 194, in
wd = ChromeDriver(d).driver()
File "D:\Program Files\Python38\lib\site-packages\atx\ext\chromedriver.py", line 77, in driver
dr = webdriver.Remote('http://localhost:%d' % self.port, capabilities)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 268, in __init
_
self.start_session(capabilities, browser_profile)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 359, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 424, in execute
self.error_handler.check_response(response)
File "D:\Program Files\Python38\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 247, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: cannot find Chrome binary

qugo9955 回复

d = u2.connect ('15edc977') # USB 链接设备。

d = uiautomator2.connect (getIp ()) # wifi 连接。

connect 的时候,要指定设备 id,或连接与电脑一致的 wifi

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册