WebView技术原理

我们知道混合应用是在原生应用里嵌套了H5页面,H5是在webview控件里的,那么我们在UI自动化时该如何定位webview里的元素呢?我们可以通过 uiautomatorviewer将webview解析出来android能识别的组件,但是这种方式在不同的手机上有可能解析的不一致,导致自动化脚本不稳定,不推荐使用这种方法。另外我们可以手机端的webview页面映射到PC端,在PC端通过将chrome://insepect 查看页面元素,推荐使用,但是注意这里需要外网环境。
如下将分析一段appium的日志来分析webview的工作原理,文章尾部附有自动化脚本及完整日志:

解析:

  1. 获取上下文列表
    在这里插入图片描述
    服务端发送命令adb shell cat /proc/net/unix获取域套接字列表。那什么是域套接字呢?
    域套接字:是unix系统里进程与进程之间通信的一种方式。客户端想要与服务端想要连接,必须有共同的套接字和相应的服务端的端口号。套接字会一直处于监听状态,监听客户端发来的请求。
    adb shell cat /proc/net/unix是获取手机端的套接字,这些套接字是用来监听外界发来的请求
    adb shell cat /proc/net/unix |grep webview显示webview的套接字,其中套接字最后的数字就是进程ID
    在这里插入图片描述
    获取到webview的进程后,通过命令adb shell ps |grep 9986查询出来该进程对应的应用
    在这里插入图片描述

  2. 匹配chromedrvier
    在这里插入图片描述
    这里是将现存的chromediver进程杀掉,并查找可以匹配webview版本的chromedriver,如果没有相对应的版本此处会报错。

  3. 查看本地和手机端的tcp连接映射关系
    adb forward --list
    adb forward 命令是查看本地和手机端端tcp连接的映射关系
    在这里插入图片描述
    结果显示本地的57973端口和手机端的webview端口进行通信
    adb forward tcp:8888 tcp:9999建立本地8888端口和手机端9999端口的映射
    adb forward --remove tcp:8888删除8888端口
    更多adb forward的使用方法参考:adb |grep forward
    注意看:日志上是将这个映射关系给抹除了,目的是防止该进程没有被正常关闭时影响接下来的操作。

  4. 启动chromedriver
    在这里插入图片描述
    这里启动起来了chromedriver,占用的是8000端口(日志没截全,可以去看文章开头的全量日志)监听的本地的5037端口,为啥占用的是8000?在日志第303行,因为我们的脚本中没有指定端口,所以appium默认选择了一个空闲的8000端口。

  5. 创建session
    这里的session是指的appium server和chromedriver之间通信的session,

  6. 转发请求,将appium server的请求转发给chromedriver
    在这里插入图片描述
    Proxying [GET /wd/hub/session/b76bb00a-43bc-4155-bd6a-ccaa3eb865b2/source] to [GET http://127.0.0.1:8000/wd/hub/session/ed7fb83742cae3d1847485e4a02ad001/source] with body: {}
    这条命令可以看出来,appium server对发到4723端口的操作,转发到了8000端口,并且session_id是appium. server 和chromedriver之间的session,本质上就是appium做了个代理,把请求进行了一次转发。

以上是我对appium 在做webview进行自动化测试时的总结,以上如有疏漏烦请各位指出,以期共同进步。

完整日志:
脚本及appium日志如下:
自动化脚本:

from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction


class TestDemoTwo:

    def setup(self):
        caps = {
   
            "platformName": "android",
            "deviceName": "test",
            "appPackage": "io.appium.android.apis",
            "appActivity": "io.appium.android.apis.ApiDemos",
            "noReset": "true"
        }

        self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        pass

    def test_webview(self):
        view = "WebView"
        self.driver.find_element(MobileBy.XPATH, "//*[@text='Views']").click()
        # print(self.driver.contexts)
        self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,
                                 f'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("{
     view}").instance(0));').click()
        # 打印上下文
        print(self.driver.contexts)
        # 定位元素及操作
        self.driver.find_element(MobileBy.XPATH, '//*[@resource-id="i am a link"]').click()
        print(self.driver.contexts)
        # 切换上下文
        self.driver.switch_to.context(self.driver.contexts[-1])
        # self.driver.find_element(MobileBy.XPATH)
        # self.driver.find_element(MobileBy.XPATH, "//*[contains(@text,'other')]").get_attribute("text")
        print(self.driver.page_source)

appium日志:

2021-10-10 08:00:36:303 [Appium] Welcome to Appium v1.15.1
2021-10-10 08:00:36:306 [Appium] Non-default server args:
2021-10-10 08:00:36:307 [Appium]   sessionOverride: true
2021-10-10 08:00:36:308 [Appium]   logFile: appium1.log
2021-10-10 08:00:36:428 [Appium] Appium REST http interface listener started on 0.0.0.0:4723
2021-10-10 08:00:51:282 [HTTP] --> POST /wd/hub/session
2021-10-10 08:00:51:283 [HTTP] {
   "capabilities":{
   "firstMatch":[{
   "platformName":"android","appium:deviceName":"test","appium:appPackage":"io.appium.android.apis","appium:appActivity":"io.appium.android.apis.ApiDemos","appium:noReset":"true"}]},"desiredCapabilities":{
   "platformName":"android","deviceName":"test","appPackage":"io.appium.android.apis","appActivity":"io.appium.android.apis.ApiDemos","noReset":"true"}}
2021-10-10 08:00:51:288 [W3C] Calling AppiumDriver.createSession() with args: [{
   "platformName":"android","deviceName":"test","appPackage":"io.appium.android.apis","appActivity":"io.appium.android.apis.ApiDemos","noReset":"true"},null,{
   "firstMatch":[{
   "platformName":"android","appium:deviceName":"test","appium:appPackage":"io.appium.android.apis","appium:appActivity":"io.appium.android.apis.ApiDemos","appium:noReset":"true"}]}]
2021-10-10 08:00:51:290 [BaseDriver] Event 'newSessionRequested' logged at 1633852851289 (16:00:51 GMT+0800 (中国标准时间))
2021-10-10 08:00:51:305 [Appium] 
2021-10-10 08:00:51:305 [Appium] ======================================================================
2021-10-10 08:00:51:306 [Appium]   DEPRECATION WARNING:
2021-10-10 08:00:51:306 [Appium] 
2021-10-10 08:00:51:307 [Appium]   The 'automationName' capability was not provided in the desired 
2021-10-10 08:00:51:308 [Appium]   capabilities for this Android session
2021-10-10 08:00:51:308 [Appium] 
2021-10-10 08:00:51:309 [Appium]   Setting 'automationName=UiAutomator2' by default and using the 
2021-10-10 08:00:51:310 [Appium]   UiAutomator2 Driver
2021-10-10 08:00:51:311 [Appium] 
2021-10-10 08:00:51:311 [Appium]   The next major version of Appium (2.x) will **require** the 
2021-10-10 08:00:51:312 [Appium]   'automationName' capability to be set for all sessions on all 
2021-10-10 08:00:51:313 [Appium]   platforms
2021-10-10 08:00:51:314 [Appium] 
2021-10-10 08:00:51:314 [Appium]   In previous versions (Appium <= 1.13.x), the default was 
2021-10-10 08:00:51:315 [Appium]   'automationName=UiAutomator1'
2021-10-10 08:00:51:315 [Appium] 
2021-10-10 08:00:51:315 [Appium]   If you wish to use that automation instead of UiAutomator2, please 
2021-10-10 08:00:51:316 [Appium]   add 'automationName=UiAutomator1' to your desired capabilities
2021-10-10 08:00:51:317 [Appium] 
2021-10-10 08:00:51:317 [Appium]   For more information about drivers, please visit 
2021-10-10 08:00:51:317 [<
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值