通过调试一些小的 Appium 官方样例,或其他博客中的样例程序,发现 Appium 大部分底层用了 selenium webdriver 进行封装,目前发现的有 WebDriver(来自 selenium-api-2.52.0.jar 的 org.openqa.selenium.WebDriver)和 AndroidDriver(来自 java-client-3.4.0.jar 的 io.appium.java_client.android.AndroidDriver)他们都可以实现对官方样例安卓程序 ContactManager.apk 的自动化回放测试。
大致就是通过命令请求 webdriver,然后 webdriver 通过浏览器的 api 去做操作,并返回响应结果。用的协议是 json wire protocol,下面简单画了个流程图,不一定准确,只是个人理解。
详细的可以参考官方 W3C 介绍:https://www.w3.org/TR/2016/WD-webdriver-20160120/
1 需要 chromedriver,之前安装过 npm 版本的 Appium 所以到本地硬盘 D: 搜索 chromedriver 发现在位置
D:\nodejs\node-global\node_modules\appium\node_modules\appium-chromedriver\chromedriver\win 的目录 2016/02/29 09:36
. 2016/02/29 09:36 .. 2016/02/29 09:36 5,285,376 chromedriver.exe 1 个文件 5,285,376 字节 2 个目录 102,209,937,408 可用字节2 然后我们在该目录下执行
D:\nodejs\node-global\node_modules\appium\node_modules\appium-chromedriver\chromedriver\win>java -Dwebdriver.chrome.driver="chromedriver.exe" -jar D:\Install\Appium\selenium-server-standalone-2.52.0.jar
11:42:46.756 INFO - Launching a standalone Selenium Server
11:42:46.999 INFO - Java: Oracle Corporation 25.60-b23
11:42:47.000 INFO - OS: Windows 10 10.0 amd64
11:42:47.014 INFO - v2.52.0, with Core v2.52.0. Built from revision 4c2593c
11:42:47.072 INFO - Driver class not found: com.opera.core.systems.OperaDriver
11:42:47.074 INFO - Driver provider com.opera.core.systems.OperaDriver is not registered
11:42:47.085 INFO - Driver provider org.openqa.selenium.safari.SafariDriver registration is skipped: registration capabilities Capabilities [{browserName=safari, version=, platform=MAC}] does not match the current platform WIN10
11:42:47.399 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
11:42:47.401 INFO - Selenium Server is up and running
3 编辑一段小的测试代码
package com_appium.my_app;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.junit.Test;
public class TestWebdriverChrome {
static WebDriver dr;
@Test
public void testChrome() {
DesiredCapabilities aDesiredcap = DesiredCapabilities.chrome();
//aDesiredcap.setBrowserName("chrome");
aDesiredcap.setPlatform(Platform.WINDOWS);
try {
dr = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), aDesiredcap);
dr.get("http://www.baidu.com");
dr.findElement(By.id("kw")).sendKeys("webdriver");
Thread.sleep(3000);
dr.quit();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
通过 Junit 执行后,将打开谷歌浏览器,自动打开百度 搜索 webdriver。日志输出如下:
11:43:06.897 INFO - Executing: [new session: Capabilities [{browserName=chrome, version=, platform=WINDOWS}]])
11:43:06.909 INFO - Creating a new session for Capabilities [{browserName=chrome, version=, platform=WINDOWS}] Starting ChromeDriver 2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4) on port 33920 Only local connections are allowed. 11:43:09.301 INFO - Done: [new session: Capabilities [{browserName=chrome, version=, platform=WINDOWS}]]
11:43:09.325 INFO - Executing: [get: http://www.baidu.com])
11:43:10.944 INFO - Done: [get: http://www.baidu.com] 1
1:43:10.984 INFO - Executing: [find element: By.id: kw])
11:43:11.028 INFO - Done: [find element: By.id: kw]
11:43:11.057 INFO - Executing: [send keys: 0 [[ChromeDriver: chrome on XP (bd7bf32a4c4977e883ebb9920d63ebe4)] -> id: kw], [webdriver]])
11:43:11.396 INFO - Done: [send keys: 0 [[ChromeDriver: chrome on XP (bd7bf32a4c4977e883ebb9920d63ebe4)] -> id: kw], [webdriver]]
11:43:14.406 INFO - Executing: [delete session: 7848fa1d-edd7-4b04-b16e-cd07188b718b])
11:43:15.932 INFO - Done: [delete session: 7848fa1d-edd7-4b04-b16e-cd07188b718b]
由此可见,代码的一个请求命令,webdriver 都会封装一个 executing,发送过去,发送成功后,再返回一个 done 表示处理成功。如果发生了异常,如找不到页面元素,则会在执行时抛异常
您需要 HttpRequester 这款火狐插件来构造模拟 http 请求 https://addons.mozilla.org/En-us/firefox/addon/httprequester/
1.首先在浏览器输入http://localhost:4444/wd/hub
通过以下方式拿到 sessionid:fc6f9497-330f-4d6c-abe0-bd0587e57101
2.拿到 session 后,就可以请求拉
首先我们用接口访问个百度,接口地址:http://localhost:4444/wd/hub/session/5c81a944-55c6-4c2a-9e01-689bc43d335d/urljson 内容:{"url":,请求 "http://www.baidu.com/"}。
post 后见下图
3.查找百度搜索的输入框
使用接口/session/{session id}/element,post 请求,json 内容:{ "using": "id", "value": "kw" }
4.查找到后,我们要往输入框输入内容
调用接口:/session/{session id}/element/{element id}/value,post 请求,json 内容:{ "value": [ "qiaoyeye" ] }
注意:element id 是第三步中的响应结果 json 中的{"ELEMENT":"0"}0 值
以上三步的请求和 json 内容
http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/url
{"url": "http://www.baidu.com/"}
http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/element
{
"using": "id",
"value": "kw"
}
http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/element/0/value
{ "value": [ "webdriver" ] }
Firefox 来说,selenium webdriver 是基于这个平台开发的,WebDriver 实现了 FireFoxDriver,无需用户下载 FireFoxDriver。
chrome 需要,chromedriver.exe
IE 需要,IEDriverServer.exe
备注:年代久远的研究 appium 时的 wiz 保存下来的网页,出处原贴已找不到了。但对于分析研究 appium macaca 类似的工具原理应该有帮助,故分享出来。
比如 升级最新 macaca-cli 可以在http://localhost:3456/
看到目前 server 端支持的 webdriver 方法,那么通过看 macaca server --verbose 或脚本的 --verbose 日志,
我们也可以发现 大量的类似的这种请求
proxy.js:52:14 [master] pid:14960 Proxy: /wd/hub/session/temp/window:POST to http://localhost:9515/wd/hub/session/0f7e2af16cfbc92f86558c78618edfc8/window:POST with body: {"name":"CDwindow-EB102075-20E4-4CC4-8621-881F04FF0D3F"}
所以 底层上基本都相似的,也应该可以通过该方式尝试理解 macaca 的工作与封装处理流程。