前言
首先我们要对App开发架构做一些简单的了解,通常App开发有三种模式分别为:Native App,Hybrid App,Web App。
Native App:使用 Android 默认(原生)控件进行开发的App,使用原生控件开发的App加载更快
Hybrid App:在 Android 原生控件基础上使用了WebView控件(需要注意的是 WebView 也是原生控件)。在 WebView 控件中允许渲染出 HTML等许多Web内容。
Web App:用户使用手机浏览器访问的网站
WebView 会出现在 Hybrid App 和 Web App之中,接下来提供两个 WebView 案例:
上图是一个 Hybrid App 的 WebView,可以看到其中有很多 android.view.View 的控件这其实是 uiautomator 识别之后强行用原生控件表达的结果,对于元素的属性也是类似,并且当遇到一些原生无法表达的属性时该属性则会被丢弃例如class,href等。同时在不同设备中强行解析的结果也可能不同。
上图是用手机浏览器打开百度首页的样式,我们可以发现其实浏览器也是在原生控件的基础上使用了 WebView 渲染了web页面。
WebView更好的分析方式
从上一节中我们可以看出使用基础的工具分析 WebView 下元素是不完整的并且同一个元素在不同的设备下元素属性可能会被识别为不一样的内容,因此我们需要寻求更精准的分析方式。
我们常见的Chrome/Edge等浏览器提供的调试工具就可以很好的帮助我们分析 WebView。
对于 Web App 我们可以随时按照以下步骤进行调试(手机浏览器默认是开启 webview 调试功能的)
- 确保 adb 可以正常连接到手机设备
- 打开 Chrome 浏览器,并且打开chrome://inspect
- 此时当我们打开手机浏览器并访问某个网址时在 Chrome 中便可以看到对应条目,点击 inspect 按钮即可进行调试。
同样的的方式适用于 Hybrid App,但对于 Hybrid App 我们需要关注应用是否允许对 WebView 进行调试,即应用代码中是否实现了以下一行代码。Webview.setWebContentsDebuggingEnabled(true);
当然通常情况下厂商为了保证应用的效率及安全通常是会默认关闭调试开关的,以下是一个参考表
平台 | 应用 webview 调试开关默认状态 |
---|---|
as 模拟器 Android 6.0 | 开 |
as 模拟器 Android 7.0及以上 | 关 |
真机 | 关 |
微信小程序内核的某些老版本 | 开 |
微信小程序内核 | 关 |
appium 操作 webview
一. capabilities
在 Appium 使用过程中,当我们对 webview 操作时会自动调用 chromedriver。那么这就这涉及到一个问题,chromedriver 需要和 webview 版本匹配才可以正常使用,但不同的应用使用的 webview 版本可能不同这就会导致我们的 chromedriver 版本也需要不停的变动。
针对这个问题 Appium 提供了一个 capability 参数 chromedriverExecutableDir
可以指定一个存放不同版本chromedriver的目录给该参数,Appium 会自动调用可用版本的 chromedriver 来执行任务。
当我们希望指定 chromedriver 时我们可以在 capability 中使用 chromedriverChromeMappingFile
参数,指名希望使用的 chromedriver。
查看应用 webview 版本
adb shell dumpsys package {package} | grep ‘versionName’
基于管理及排查的考虑,我们可以在 capabitliy 中加入 showChromedriverLog
参数,该参数会让 Appium 日志中加入 chromedriver 相关的日志。
capabilities = {
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appPackage": "io.appium.android.apis",
"appActivity": ".ApiDemos",
"chromedriverExecutableDir": "/Users/ya/wangyun/AppiumOC/_driver",
"showChromedriverLog": True
}
二. contexts
Appium 中会涉及到一个 contexts 的概念,当在纯原生的页面时我们处在一个唯一的名为 NATIVE_APP
的 context 之中。
但当我们所在页面有 webview 时便会多出一个 context,该 context 通常名为 WEBVIEW_io.{package}
,package 为应用包名。这个多出的 context 就是渲染出的 web 页面。
查看 context 的方法:
driver.contexts
:查看当前页面所有的 contextdriver.current_context
:查看当前所在的 context
因此,当我们需要操作 webview 内元素时需要首先进入到其对应的 context 中再进行操作。
切换 context 的方法:
self.driver.switch_to.context(contextName)