ATX ATX-uiautomator2 实现 webview 的操作

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

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 条回复 时间 点赞
qugo9955 回复

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

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

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

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

linpengcheng 回复

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

qugo9955 回复

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

Mr.武 回复

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

请教下 我运行例子里面的代码,启动的怎么是 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()

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

Mr.武 回复

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

lgh75560 回复

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

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

通过这个 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 是采用其他的方法呢?

finfou 回复

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

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)])

linpengcheng 回复

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

Margaret 回复

先启动 webdriver 在 remote

Margaret 回复

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

沈裕婷 回复

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

Margaret 回复

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

Margaret 回复

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

linpengcheng 回复

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

Margaret 回复

9515 被占用了?

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() 就报错了

linpengcheng 回复

可以了,感谢感谢

yideng-dst 回复

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


删掉就报这个错了

yideng-dst 回复

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

yideng-dst 回复

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


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

zhunt 回复

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

linpengcheng 回复

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

zhunt 回复

你别和我说你用的是微信

linpengcheng 回复

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

zhunt 回复

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

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

xiaoquanzi 回复

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

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

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

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

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

回复

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

云敛晴空 回复

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

回复

没怎么试过😂

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 切换的部分

回复

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

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 的时候报错

塔克米 回复

499563266 加群讨论吧 atx-uiautomator2 的

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 有偿

Java 可以使用吗?

linpengcheng 回复

谢谢大佬!可以了!

JKzhishui 回复

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


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

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

设备有没有连在电脑上?

云敛晴空 回复

请问你的问题解决了么。

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

云敛晴空 回复

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

linpengcheng 回复

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

云敛晴空 回复

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

linpengcheng 回复


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

云敛晴空 回复

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

linpengcheng 回复


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

云敛晴空 回复

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

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

不错不错

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