背景

移动应用可以粗分为三种:原生应用(native app), 网页应用(web app,或HTML5 app),以及它们的混血儿——混合模式移动应用(hybrid app)。

什么是Hybrid Mobile App

Hybrid app从外观上来看是一个native app,实则只有一个UIWebView,里面访问的是一个web app,如新闻类和视频类的应用普遍采取该策略:native的框架加上web的内容。不同于native app需要针对不同的平台使用不同的开发语言(如使用Objective-C、Swift开发iOS应用,使用Java等开发Android应用,使用C#开发Windows Phone应用),hybrid app允许开发者仅使用一套网页语言代码(HTML5+CSS+JavaScript),即可开发能够在不同平台上部署的类原生应用 。由于hybrid app结合了native app良好用户交互体验和web app跨平台开发的优势,能够显著节省移动应用开发的时间和成本,hybrid app得到越来越多公司的青睐。

参考资料:

native APP,hybrid APP和web APP:https://blog.csdn.net/weixin_41646716/article/details/82190822

怎么判断是Webview控件

WebView的测试

主要作用在混合(Hybrid)的应用,一部分是原生界面和代码,而另一部分是内嵌网页,比如微信、支付宝,内嵌了一个浏览器内核,由浏览器内核实现的,安卓应用中的内嵌的展示网页内容的模块,我们称之为webview。

Appium之WebView自动化:https://www.cnblogs.com/peipei-Study/p/12012422.html

准备测试机

  • 模拟器,Android Studio自带的Android 6.0版本模拟器,更高版本不支持
  • genymotion的Android 6.0版本模拟器:https://www.genymotion.com
  • 木木模拟器、bluestacks默认不支持
  • 真机打开webview开关

    app修改编译 ---- 需要添加webview调用 ---- 对webview对象加入setWebContentsDebuggingEnable的调用

    直接让开发人员在下面这段代码中加入一句代码:
 protected void onCrete(Bundle saveInstanceState){

        super.onCreate(savedInstanceState);

        WebView myWebView = (WebView) findViewById(R.id.xxxwebview);

        myWebView.setWebContentsDebuggingEnabled(true);    #  加上这句代码

 };

如果不知道怎么说,简单总结一句话:“帮忙加一下webview的debug调用”就好。

观察webview内部的工具:chrome inspect

在chrome中输入:chrome://inspect



使用chrome62版本,其他版本有bug,观察到webview内部结构混乱



需要代理上网

chrome://inspect/#devices HTTP/1.1 404 Not Found 空白页问题:

http://centphp.com/view/165

点击 inspect 按钮,新窗口HTTP/1.1 404 Not Found,出现空白页,这是因为Chrome 的devtools 需要联网下载对应的WebView的测试环境,appspot.com在国内不能直接访问。三种解决方法:

  • 方法一:下载devtools 的inspect的 离线开发者调试工具包。

  • 方法二: 修改网络连接,修改hosts文件。

  • 方法三:使用第三方的chromium内核的浏览器,如QQ浏览器。

进入inspect后

使用Chrome://inspect调试 Android 设备上Webview

https://www.jianshu.com/p/66896bec620e

下载对应的chromedriver版本,使用caps配置chromedriver版本

查看webview版本

  • chrome://inspect/#devices中可以看到

  • 在手机设置中查看

  • 使用命令查看

运行脚本时报错:

selenium.common.exceptions.WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: No Chromedriver found that can automate Chrome ‘64.0.3282’. See https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md for more details.

https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md中提到可以在https://raw.githubusercontent.com/appium/appium-chromedriver/master/config/mapping.json中找到Chromedriver版本及其匹配的最低Chrome版本的列表,但是.json这个URL访问不了,这个URL应该可以看到类似下面的版本对应说明。


官方的说明原文

Appium通过管理Chromedriver 实例并在必要时向其代理命令来支持自动化Android网页(在Chrome和内置浏览器中)和受Chrome支持的混合应用程序。它与最新版本的Chromedriver捆绑在一起 ,并通过npm软件包appium-chromedriver (Github:appium-chromedriver)安装。

随着Chromedriver的每次更新,最低支持的Chrome版本都会增加,从而使旧版本的设备通常无法通过捆绑版本自动执行。在Appium服务器日志中,将出现如下错误:

An unknown server-side error occurred while processing the command.

Original error: unknown error: Chrome version must be >= 55.0.2883.0

要解决此问题,必须为Appium提供正确的Chromedriver二进制文件,该二进制文件应与 被测设备上运行的Chrome引擎版本匹配。阅读以下Chromedriver/Chrome compatibility主题,以了解有关查找匹配的Chromedriver可执行文件的更多信息。

有几种方法可以为Appium提供自定义的Chromedriver:

1.安装服务器时

提供--chromedriver_version包含实际版本号的命令行参数

npm install appium --chromedriver_version="2.16"

或在CHROMEDRIVER_VERSION环境变量中指定Chromedriver版本,例如,

CHROMEDRIVER_VERSION=2.20 npm install appium

也可以将其设置为LATEST获取最新版本。

2.启动服务器时

可以在运行时通过指定--chromedriver-executable服务器标志来指定Chromedriver版本 ,以及通过手动下载并放入服务器文件系统的Chromedriver可执行文件的完整路径,例如

appium --chromedriver-executable /path/to/my/chromedriver

3.开始会话时(手动发现)

通过提供chromedriverExecutable上限,可以在会话功能中指定Chromedriver版本,该 上限包含匹配的Chromedriver可执行文件的完整路径,必须手动下载该文件并将其放入服务器文件系统。有关更多详细信息,请参见http://appium.io/docs/zh-CN/writing-running-appium/caps/

4.开始会话时(自动发现)

如果本地文件系统上不存在目标Chrome引擎的版本,则Appium也可以尝试检测目标Chrome引擎的版本并自动为其下载匹配的chromedriver。阅读Automatic discovery of compatible Chromedriver下面的主题以获取更多详细信息。

Chromedriver / Chrome兼容性

您可以在https://raw.githubusercontent.com/appium/appium-chromedriver/master/config/mapping.json中找到Chromedriver版本及其匹配的最低Chrome版本的列表。

从2.46版开始,Google更改了Chromedriver版本控制的规则,因此现在主要的Chromedriver版本对应于可以自动执行的主要Web视图/浏览器版本。按照版本选择文档以手动找到Chromedriver,如果其主要版本等于或高于73,则该浏览器将支持您当前的浏览器/网络视图。

要查找较低版本的Chromedriver(低于73)的最低支持的浏览器,请获取Chromium 源代码,查看发布确认,然后检查kMinimumSupportedChromeVersion 文件中的变量src/chrome/test/chromedriver/chrome/version.cc。(要查找发布承诺,可以使用git log --pretty=format:'%h | %s%d' | grep -i "Release Chromedriver version"。)

可用的Chromedriver版本和发行说明的完整列表在此处。

自动发现兼容的Chromedriver

从Appium 1.8.0开始,Appium可以为测试中的Chrome版本选择正确的Chromedriver。虽然Appium仅在发布Appium版本时与最新发布的Chromedriver捆绑在一起,但可以下载更多Chromedriver版本并将其放置在Appium安装中(不建议这样做,因为升级Appium会删除它们)或放置在自定义位置可以向Appium指示chromedriverExecutableDir所需的功能。此功能是您放置一个或多个Chromedriver可执行文件的目录的绝对路径。

同样,由于可能会发布新版本的Chromedriver,而发布Appium版本时还没有,因此可以通过chromedriverChromeMappingFile 所需功能将自定义的Chromedriver映射到它们支持的最低Chrome版本。这应该是其中包含映射的文件的绝对路径。文件的内容需要可解析为JSON对象,例如:

{

“ 2.42 ”:“ 63.0.3239 ”,

“ 2.41 ”:“ 62.0.3202 ”

}

从Appium 1.15.0开始,可以chromedriverExecutableDir从官方的Google存储中自动下载必要的chromedriver 。该脚本将自动搜索支持给定浏览器/ Web视图的最新chromedriver版本,将其下载(哈希总和也将针对下载的档案进行验证)并添加到chromedriverChromeMappingFile映射中。您需要做的所有事情都是在chromedriver_autodownload启用功能的情况下执行服务器(例如appium --allow-insecure chromedriver_autodownload)。您还可以查看“安全性”文档,以获取有关如何控制潜在的不安全服务器功能的更多详细信息。

解决网络问题

安装Appium后,需要下载Chromedriver,因此可能存在导致安装失败的网络问题。

默认情况下,从中检索Chromedriver https://chromedriver.storage.googleapis.com/。要使用ChromeDriver二进制文件的镜像,请使用npm config属性chromedriver_cdnurl。

npm install appium-chromedriver --chromedriver_cdnurl = http://npm.taobao.org/mirrors/chromedriver

或将属性添加到.npmrc文件中。

chromedriver_cdnurl = http://npm.taobao.org/mirrors/chromedriver

另一种选择是使用PATH变量CHROMEDRIVER_CDNURL。

CHROMEDRIVER_CDNURL = http://npm.taobao.org/mirrors/chromedriver npm install appium-chromedriver

可能还需要调整网络代理和防火墙设置,以允许进行下载。

W3C支持

Chromedriver直到75版才遵循W3C标准。如果遇到类似此问题的Proxy命令错误,请更新您的Chromedriver版本。旧的Android设备不能使用较新的Chrome驱动程序。如果使用“移动JSON有线协议”运行测试,则可以避免该错误。由于主要版本75 W3C模式是Chromedriver的默认模式,尽管它仍可以根据传递的会话功能切换为JSONWP模式。您可以从下载中阅读Chromedriver中的W3C支持历史记录。


chromedriver下载地址:https://chromedriver.storage.googleapis.com/index.html

在Appium测试切换webview步骤

以下是在Appium测试中与webview对话所需的步骤:

  • 导航到应用程序中web页面
  • 获取上下文列表,它返回一个我们可以访问的上下文列表,例如:NATIVE_APP或WEBVIEW_1
  • 切换到你要操作的webview,原来是在NATIVE_APP,切换到WEBVIEW_1,进行相应操作
  • 操作完后,返回到原来的app view(通常为NATIVE_APP)

以雪球app进行演示

需要进行的操作,点击“交易”,进入一个webview页面,输入手机和验证码后,点击返回按钮







地址:https://github.com:yuruotong1/11period-Selenium-homework

from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait class TestWebview:
def setup(self):
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
caps['autoGrantPermissions'] = True
caps['noReset'] = True
caps['chromedriverExecutable'] = 'D:/develop/chromedriver/2.20.exe'
self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
self.driver.implicitly_wait(15) def test_webview(self):
# 点击交易
self.driver.find_element(By.XPATH, '//*[@text="交易" and contains(@resource-id, "tab_name")]').click()
# 切换到webview
self.driver.switch_to.context(self.driver.contexts[-1])
# 切换到webview后,使用selenium定位,点击港美股开户
self.driver.find_element(By.CSS_SELECTOR, ".trade_home_xueying_SJY").click()
# 切换窗口
WebDriverWait(self.driver, 30).until(lambda x: len(self.driver.window_handles) > 3)
self.driver.switch_to.window(self.driver.window_handles[-1])
# 显式等待
WebDriverWait(self.driver, 30).until(expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, '[placeholder="请输入手机号"]')))
# 输入手机号/验证码
self.driver.find_element(By.CSS_SELECTOR, '[placeholder="请输入手机号"]').send_keys("12345")
self.driver.find_element(By.CSS_SELECTOR, '[placeholder="请输入验证码"]').send_keys("555555")
# 切换回native窗口
self.driver.switch_to.context(self.driver.contexts[0])
# 点击返回按钮
self.driver.find_element(By.ID, "action_bar_back").click()

思寒老师上课的例子:

def test_webview_context(self):
self.driver.find_element(By.XPATH, "//*[@text='交易' and contains(@resource-id, 'tab')]").click() # 首次做测试的时候,用于分析当前的上下文
# for i in range(5):
# print(self.driver.contexts)
# sleep(0.5)
# print(self.driver.page_source) # 坑1:webview上下文出现大概有3s的延迟, android 6.0默认支持,其他的需要打开webview调试开关
# adb shell cat /proc/net/unix | grep webview
WebDriverWait(self.driver, 30).until(lambda x: len(self.driver.contexts) > 1)
# 坑2:chromedriver的版本与chrome版本必须对应
# 坑3:chromedriver可能会存在无法对应chrome版本的情况,需要使用caps的mapping file或者直接chromedriverExecutable
# /Users/seveniruby/projects/chromedriver/all/chromedriver_2.20 --url-base=wd/hub --port=8000 --adb-port=5037 --verbose self.driver.switch_to.context(self.driver.contexts[-1])
# print(self.driver.page_source)
# print(self.driver.window_handles) # 使用chrome inspect分析界面控件,需要代理、需要chrome62及以前的版本都可以
# Proxying [POST /wd/hub/session/b2fe71d1-3dff-45df-bc2c-52e9195d5b98/element] to [POST http://127.0.0.1:8000/wd/hub/session/790fc7cf4c186545679b24ce5bbd9699/element] with body: {"using":"css selector","value":".trade_home_info_3aI"}
self.driver.find_element(By.CSS_SELECTOR, ".trade_home_info_3aI").click() # 首次做测试的时候,用于分析当前的窗口
# for i in range(5):
# print(self.driver.window_handles)
# sleep(0.5) # 坑4:可能会出现多窗口,所以要注意切换
WebDriverWait(self.driver, 30).until(lambda x: len(self.driver.window_handles) > 3)
self.driver.switch_to.window(self.driver.window_handles[-1])
phone = (By.ID, 'phone-number') # html定位的常见问题,元素可以找到的时候,不代表可以交互,需要用显式等待
WebDriverWait(self.driver, 60).until(expected_conditions.visibility_of_element_located(phone))
self.driver.find_element(*phone).send_keys("15600534760")

https://blog.csdn.net/lb245557472/article/details/93590156提到的例子:

from appium import webdriver

mobile_desired_caps = {
'platformName': 'Android',
'platformVersion': '7.0',
'deviceName': 'your device name',
"app": r"your.apk",
# 指定Chromedriver存放的地址,或者下边的路径,二者其一即可
"chromedriverExecutableDir": r"C:\path",
# "chromedriverExecutable": r"C:\path\chromedriver.exe",
# 声明中文
"unicodeKeyboard": 'True',
# 声明中文,否则不支持中文
"resetKeyboard": 'True',
# 执行时不重新安装包
'noReset': 'True',
'automationName': 'uiautomator2',
'appPackage': 'your package',
'appActivity': 'your App activity'
} driver = webdriver.Remote('http://localhost:4723/wd/hub', mobile_desired_caps)
# 点击进入到webview页面
driver.find_elements_by_id("id").click()
# 切换到 webview
webview = driver.contexts[-1]
driver.switch_to.context(webview)
print "###########################################"
print driver.contexts
# [u'NATIVE_APP', u'WEBVIEW_xxxxxxxxx']
# 判断webview上的元素是否存在
print driver.find_element_by_id("btnLogoutConfirmation").is_displayed()
# 返回到原生view
driver.switch_to.context(driver.contexts[0])

Appium WebView控件定位的更多相关文章

  1. 转载:Robotium之Android控件定位实践和建议(Appium/UIAutomator姊妹篇)

    来源于:http://blog.csdn.net/zhubaitian/article/details/39803857 1. 背景 为保持这个系列的一致性,我们继续用SDK自带的NotePad实例应 ...

  2. Robotium之Android控件定位实践和建议(Appium/UIAutomator姊妹篇)

    本人之前以前撰文描写叙述Appium和UIAutomator框架是怎样定位Android界面上的控件的. UIAutomator定位Android控件的方法实践和建议 Appium基于安卓的各种Fin ...

  3. 【转】Appium基于安卓的各种FindElement的控件定位方法实践

    原文地址:http://blog.csdn.net/zhubaitian/article/details/39754041#t11 AppiumDriver的各种findElement方法的尝试,尝试 ...

  4. Appium基于安卓的各种FindElement的控件定位方法实践和建议

    AppiumDriver的各种findElement方法的尝试,尝试的目标应用是SDK自带的Notepad应用. 1. findElementByName 1.1 示例 el = driver.fin ...

  5. Appium基于安卓的各种FindElement的控件定位

    转自:http://www.2cto.com/kf/201410/340345.html 1. findElementByName 1.1 示例 ? 1 2 el = driver.findEleme ...

  6. appium 控件定位

    转自:http://www.2cto.com/kf/201410/340345.html AppiumDriver的各种findElement方法的尝试,尝试的目标应用是SDK自带的Notepad应用 ...

  7. appium简明教程(10)——控件定位基础

    狭义上讲,UI级的自动化测试就是让机器代替人去点来点去的过程. 但机器去点什么(点上面还是点左边),怎么点(是长按还是轻触),这些东西是必须由代码的编写者所指示清楚的. 控件定位就是解决机器点什么的问 ...

  8. Appium自动化(7) - 控件定位工具之Appium 的 Inspector

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 上一篇文章介绍了另一块控件定 ...

  9. appium自动化测试(3)-控件定位&中文输入

    参考-控件定位 http://www.2cto.com/kf/201410/340345.html appium接口 http://appium.io/slate/en/master/?python# ...

随机推荐

  1. S3C2440—12.按键中断

    文章目录 一. 总体 二. CPSR设置 三. 中断源设置 四. 中断控制器设置 五. C中断处理函数 六. 汇编IRQ异常处理程序 七. 源码 一. 总体 要驱动按键中断控制LED亮灭,程序要进行如 ...

  2. flutter升级2.0

    前言 flutter2.0版本带来了很多变化,特别是加入了空安全,升级后的大片报错,让大家望而却步. 现在距2.0发布已经快半年了,大部分插件也支持了空安全,而我们的项目却因为版本低,用不上新东西,所 ...

  3. NOIP 模拟 9 斐波那契

    题解 这是一道推规律的题. 首先,这道题送分不少,先考虑 \(70pts\),直接暴力 \(\mathcal O(n)\) 建边,\(\mathcal O(logn)\) 求 \(lca\) 其次对于 ...

  4. linux 的删除

    1,删除 命令行 rm -rf 文件夹名称 2,下载 wget 网址 -------------------- 查找ES进程号 ps -ef | grep elastic kill -9 3250 3 ...

  5. COM组件的使用方法

    https://prismlibrary.com/docs/wpf/converting-from-7.html Requirement: 1.创建myCom.dll,该COM只有一个组件,两个接口I ...

  6. C#基础知识---匿名方法使用

    一.匿名方法使用 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Tex ...

  7. C#---OleDbHelper

    /// <summary> /// OleDbServer数据访问帮助类 /// </summary> public sealed class OleDbHelper { pu ...

  8. Quartz任务调度(1)概念例析快速

    实例解析概念 在quartz中,有几个核心类和接口:Job.JobDetail.Trigger.Calendar.Scheduler.下面我们结合实例来分析这些类的角色定位.现在我们有一个新闻网站,它 ...

  9. 辗转相除 求最大公约数!or 最小公倍数

    求最大公约数和最小公倍数的经典算法--辗转相除法描述如下: 若要求a,b两数的最大公约数和最小公倍数,令a为a.b中较大数,b为较小数,算法进一步流程: while(b不为0) { temp=a%b: ...

  10. Spring源码解析之ConfigurationClassPostProcessor(三)

    在上一章笔者介绍了ConfigurationClassParser.doProcessConfigurationClass(...)方法,在这个方法里调用了processImports(...)方法处 ...