• 【App自动化测试】(十四)Android WebView测试方法



    1. webview 架构与分析方法

    1.1 webview与Hybrid开发

    在这里插入图片描述

    1.1.1 移动APP三种开发模式

    1. Native APP(原生应用)

    使用Android 提供的默认控件所开发出来的APP,如TextView、imageview、listview等。

    优点:android自带SDK组件开发,与android契合度高,速度快,性能好

    缺点:开发成本高,上线时间不固定,影响敏捷交付,新版本更新需要App Store下载。

    1. Hybrid App (混合应用)

    即使用Android原生控件,也包含特殊组件WebView。WebView提供了渲染HTML的功能,因此可以展示出一套新的渲染体系。混合型开发先使用原生app做一层包裹,如启动界面,主界面,进入后会通过webview的控件去加载网页。因此后续开发中就可以使用各种H5的开发方式去进行开发。

    目前中国大部分APP的开发模式都是混合型的。例如微信、支付宝,原生界面是比较核心的界面,但是有大量细小功能,如果全部放在移动端中会非常庞大,因此这些功能会使用webview来加载一个远程网址,从而实现更多功能的装载,这样也有利于实时更新,如远程变化后,本地渲染就会相应的发生变化。

    优点开发成本中,性能中等,基于原生APP开发衍生而来,开发和更新不需要上线可在后台进行热启动。

    1. Web App

    主要方式是使用H5去开发,用户使用手机浏览器去访问。经过定制开发,专门为手机浏览器进行设计的。

    优点开发成本最低,性能差,可随时进行部署使用

    1.1.2 native原生开发

    1.1.2.1 native原生开发说明

    在这里插入图片描述

    例如图中,通过Android Studio查看开发方式,某些界面开发方式使用Activity,里面会使用类似EditText、TextView这种由Android默认提供的一套组件库,这种就是native原生开发。

    1.1.2.2 native原生开发组件

    在这里插入图片描述

    native原生开发组件特征:通过UI Automator Viewer 可以查看到元素的class属性,原生组件的class属性名称中有android.widget。

    1.1.3 Hybrid混合开发webview展示

    1.1.3.1 Hybrid混合开发中的app webview组件

    在这里插入图片描述

    webview组件特征:通过UI Automator Viewer查看class属性,可以看出class的的名称android.webkit.webview

    1.1.3.2 webview开发代码展示

    通过Android提供的webview组件来加载html文件,可以是本地网页,也可以是远程网页。
    在这里插入图片描述

    1.1.3.3 Hybrid混合开发中的app webview组件

    在这里插入图片描述

    UIautomationviewer会强制的把H5的控件的一些属性翻译成原生控件的属性。如果是文本翻译成textview;如果是图片则翻译成image之类的;如果是超链接这种特殊控件,且原生组件中没有对应类型的,则统一翻译成android.view.View.

    1.1.4 基于webview开发的程序

    1.1.4.1 微信小程序的主流架构

    在这里插入图片描述

    1.1.4.2 支付宝小程序

    在这里插入图片描述

    图示中组件名称为com.uc.webview.export.WebView,不是Android默认的android.webkit.webview说明有团队在默认的webview的基础之上做了二次开发。

    识别webview的小Tip:

    1. 正常都会有保留WebView的名称,就算做了二次开发一般也会保留此名称。
    2. 页面组件中名称会存在View这种,说明有部分非原生组件未被UI Automator View识别,并翻译成了View。
    1.1.4.3 web应用中的浏览器webview组件

    在这里插入图片描述

    上图说明,手机浏览器也是原生app里面包括了webview组件,这个webview的组件去加载了远程的html。

    1.1.5 总结:native视角下的webview控件

    • uiautomator 框架把 webview 组件“翻译”成了原生组件
      • uiautomatorviewer、appium desktop、weditor 等都可以分析
      • uiautomatorviewer 对java 版本有要求,需要 1**.8.0 60以下的版本**
      • uiautomatorviewer 首次分析 webview 组件时需多刷新一次
    • 控件转换
      • html 控件尽量用原生控件表达,比如文本转 TextView,图片转 lmage
      • 无适合原生控件表达的html控件用android view.View表达
    • 属性转换
      • html 控件中的属性用原生控件表达,根据不同的版本转换为 resource-id 、content-desc text
      • native 无法表达的 html 属性会丟失,比如 class href src 等属性

    1.2 webview组件的真正分析方法

    1.2.1 webview组件分析方法说明

    • uiautomatorviewer的分析是不完整的

    • 浏览器的分析工具可以分析webview控件完整信息

    1.2.2 如何分析webview控件?

    1.2.2.1 第一步:打开webview调试开关
    1.2.2.1.1 代码中的webvie调试开关

    在这里插入图片描述

    设置成true,打开webview调试开关。

    1.2.2.1.2 各平台webview组件的调试开关开启情况
    平台webview组件调试开关应用webview组件调试开关可调式
    as模拟器android6.0默认开启✔️可调式
    as模拟器android7.0及以上默认关闭关闭❌不可调试
    as模拟器android7.0及以上默认关闭开启✔️可调式
    真机默认关闭关闭❌不可调试
    真机默认关闭开启✔️可调式
    微信小程序内核 某些老版本默认开启✔️可调式
    微信小程序内核 默认关闭❌不可调试
    1.2.2.1.3 强行法开webview调试开关的方法
    • root手机修改webview内核xposed
    • 使用沙箱,hook webview组件的调用virtualapp
    • 自己编译android系统

    ps:因为这些方法不常用且有各种局限,所以使用不多,仅限于安全领域研究。使用最多的办法是通过后门开启调试开关。

    1.2.2.2 第二步:打开带有webview的页面

    webview页面必须要先打开,webview页面只有先打开的情况下,分析工具中的相关内容才会出现。
    在这里插入图片描述

    1.2.2.3 第三步:打开浏览器的分析工具

    分析工具类型

    • chrome://inspect
      • 最优选择,但是关键组件上使用的是远程软件,需要翻墙,因此对于我们来说不好处理
    • 【推荐】edge://inspect
      • 使用与chrome相同的内核,界面与调试风格两者十分相似,并且edge还解决chrome中的一些bug。
    • firefox about:debugging
      • 功能也比较强大,但是因为技术上使用的与chrome不同,存在很大的差异,因此使用过程中不太好适应
    1.2.2.4 示例

    操作内容:使用手机浏览器,打开百度网站,进行页面元素分析。

    注意:

    1. 浏览器是默认打开webview调试开关的。打开任意网站都能够被分析到
    2. 示例中使用的模拟器是MuMu。
    3. 真机中的调试方法和当前一直,确保被调试的手机app的webview调试开关已经开启。

    第一步:手机上打开webview网页
    在这里插入图片描述

    第二步:使用 edge://inspect 进行分析

    • 检测到webview后,点击对应页面信息下的inspect

    在这里插入图片描述

    • 然后会跳转到调试界面

    在这里插入图片描述

    2. webview自动化测试

    2.1 webview自动化测试方法

    方式技术栈优点缺点
    原生自动化uiautomator
    appium
    atx
    简单;
    不依赖webview调试开关开启。
    不易维护(对于H5的大部分属性,翻译后存在属性丢失的可能性,非常不利于维护)
    web自动化selenium
    chromedriver
    minitest
    易维护1. 不适合混合开发(大部分APP都是混合型的,会导致流程割裂,出现原生是一部分,web是另外一部分的情况。如果大部分逻辑是在web里的,那可以使用此方法。);
    2. 依赖webview调试开关开启。
    混合自动化appium易维护,通用。1. 技术复杂(因为要维持原生和web两套机制,因此技术比较复杂);
    2. 依赖webview调试开关开启。

    2.2 混合自动化技术原理

    混合自动化技术原理示意图:

    在这里插入图片描述

    • appium使用多引擎管理自动化,维持一套driver两套session机制。
    • 使用chromedriver自动化webview组件。
    • 使用native方式自动化native控件。

    Appium本身用多个引擎管理自动化,对不同的自动化类型选择不同引擎去进行处理。

    Appium自动化测试原理示意图:

    在这里插入图片描述

    2.3 appium webview 自动化测试前提

    论坛帖子:chromedriver下载地址与webview自动化关键代码

    查看Andriod内置浏览器WebView版本

    1. 手机上设置中查看

      • 设置–>应用程序管理–>全部–>Android System WebView
        在这里插入图片描述
    1. 电脑Chome浏览器的devTools中查看

      • 连接设备到电脑,打开Android设备的开发者模式,并勾选USB调试授权PC连接到Android设备。
      • 在edge浏览器打开:edge://inspect/#devices
      • 在设备端运行进行了如下设置(开启远程调试)的Webview的demo
        在这里插入图片描述
    1. adb指令查看(前提,已安装android sdk环境)

      • 连接设备到电脑,打开Android设备的开发者模式,并勾选USB调试授权PC连接到Android设备。
      • 打开win+R 输入cmd打开命令窗口,输入指令:adb shell am start -a android.intent.action.VIEW -d https://liulanmi.com/labs/core.html
      • 查看手机上显示的内核版本
        在这里插入图片描述

    2.3.1 前提一:chromedriver安装

    • 如果未安装chromedriver会报错,报错内容如下:

    No Chromedriver found that can automate Chrome ‘x.x.xxxx’. You could also try to enable automated chromedrivers download server feature. See appium/chromedriver.md at master · appium/appium · GitHub 96 for more details.

    2.3.2 前提二:chromedriver版本选择正确

    unknown error:Chrome version must be >=x.x.xxxx

    • app内置webview组件可能会跟系统默认自带的webview组件不一致,以app使用的webview为准

    2.3.3 前提三:appium capability参数设置

    因为APP内置的chrome webview的版本不一定与手机浏览器上的版本一致,因此chrome driver的版本在appium中是不能写死的,利用appium的chromedriver自动发现机制,让appium自动的去找适合的chromedriver。

    appium chromedriver 自动发现机制中常用的appium capability参数参数:

    • chromedriverExecutableDir: 指定 chromedriver 可执行文件集合的目录
      • 将可用的chromedriver放在此目录下,当appium发现此配置项后,会去目录中寻找合适的chromedriver。
    • chromedriverChromeMappingFile: 允许显式指定版本对应关系
      • 强行指定一个版本的chromedriver去测特定的webview版本
    • showChromedriverLog: 让appium 日志展示 chromedriver 的日志方便排查

    appium capability参数设置 ——python:

    def setup(self):
            desired_caps = {
            "platformName":"Android",
            "deviceName":"emulator-5554",
            "appPackage": "com.example.android.apis",
            "appActivity":".ApiDemos",
            "chromedriverExecutableDir":"E:\chromedriver_webview_test",
            "chromedriverChromeMappingFile":"E:\chromedriver_webview_test\mapping.json",
            "showChromedriverLog":True
            }
            self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
            # 使用隐式等待
            self.driver.implicitly_wait(10)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    appium capability参数设置 ——java:

    //简单方案(不推荐):把chromedriver版本写死
    	     caps.setCapability("chromedriverExcutable","E:\chromedriver_webview_test\chromedriver_2.42");
    //完善的自动发现机制
    			caps.setCapability("chromedriverExecutableDir","E:\chromedriver_webview_test");
    			caps.setCapability("chromedriverChromeMappingFile","E:\chromedriver_webview_test\mapping.json");
    			caps.setCapability("showChromedriverLog",True);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4 appium context 上下文机制

    • appium context上下文机制:

      怎么在原生和webview之间进行切换? 当前原生APP名为native,代表当前属于原生自动化环境下,当通过api切换到webview后,会有一个“WEBVIEW_XXXX”格式的进程名,说明当前处于webview自动化环境下。利用不同的名称来识别是做原生测试还是webview测试。

    • Api说明:

      • 展示所有的上下文 :contexts ,第一个是原生 NATIVE,剩下的为 webview
      • 获得当前的上下文 :current_context
      • 切换上下文: switch_to.context('WEBVIEW_XXXX')

    2.5 webview自动化演示代码Python版

    from appium import webdriver
    from appium.webdriver.common.appiumby import AppiumBy
    from selenium.webdriver.support.wait import WebDriverWait
    """
    模拟器:avd模拟器
    测试测试:模拟器再带的ApiDemos
    """
    
    
    class TestWebView:
        def setup_class(self):
            desired_caps = {}
            desired_caps['platformName'] = 'Android'
            desired_caps['platformVersion'] = '6.0'
            desired_caps['deviceName'] = 'emulator-5554'
            desired_caps['appPackage'] = 'com.example.android.apis'
            desired_caps['appActivity'] = '.ApiDemos'
            desired_caps['noReset'] = 'true'
    	#python appium client 2.x 会默认使用w3c,因此此处使用chromeOptions参数吧w3c
            desired_caps['chromeOptions']={'w3c':False}
            #关键部分:设置chromedriver所在路径
            desired_caps['chromedriverExecutableDir']='E:\chromedriver_webview_test'
            #设置显式指定chromedriver和webview版本对应关系
            #desired_caps['chromedriverChromeMappingFile']='E:\chromedriver_webview_test\mapping.json'
            #开启chromedriverlog
            desired_caps['showChromedriverLog']=True
            self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
            # 使用隐式等待
            self.driver.implicitly_wait(10)
    
        def teardown(self):
            self.driver.quit()
    
        def test_webview(self):
            self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,"new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text(\"Views\").instance(0))").click()
            self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,"new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text(\"WebView\").instance(0))").click()
            #打印上下文情况
            #['NATIVE_APP', 'WEBVIEW_com.example.android.apis']
            print(self.driver.contexts)
            #webview组件加载慢的时候不一定会及时出现webview上下文,最好显示等待
            WebDriverWait(self.driver,5).until(lambda driver:len(self.driver.contexts)>1)
            #最好显示指定,在多进程同时有webview的时候,最后一个context不一定是当前app的webview
            self.driver.switch_to.context('WEBVIEW_com.example.android.apis')
    
    	#局部导入By
            from selenium.webdriver.common.by import By
            self.driver.find_element(By.LINK_TEXT,'Hello World! - 1').click()
    
    	#查看当前所在context
            #WEBVIEW_com.example.android.apis
            print(self.driver.current_context)
    
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    Vue2(一):Vue介绍、模板语法、数据绑定、el和data的两种写法、MVVM、数据代理、事件
    华为回击:制裁无法阻挡中国科技创新 | 百能云芯
    JAVA计算机毕业设计音乐播放器Mybatis+源码+数据库+lw文档+系统+调试部署
    金仓数据库KingbaseES客户端编程接口指南-JDBC(4. JDBC 创建语句对象)
    【Azure 事件中心】Azure Event Hub 新功能尝试 -- 异地灾难恢复 (Geo-Disaster Recovery)
    MySQL 定时备份
    心理月刊杂志心理月刊杂志社心理月刊编辑部2022年第11期目录
    Wordpress模板主题中functions.php常用功能代码与常用插件(持续收集整理)
    JavaScript爬虫程序实现自动化爬取tiktok数据教程
    [机缘参悟-33]:眼见不一定为实,大多数时候“眼见为虚”
  • 原文地址:https://blog.csdn.net/gjj920318/article/details/127997306