Appium 客户端(Client)完全解读:客户端-服务器架构、WebDriver 协议与多语言客户端库实战
【免费下载链接】appiumCross-platform automation framework for all kinds of apps, built on top of the W3C WebDriver protocol项目地址: https://gitcode.com/GitHub_Trending/ap/appium
Appium 基于 W3C WebDriver 规范实现了客户端-服务器(Client-Server)架构:服务器端由 Appium 本体与其驱动程序、插件组成,负责在真实设备上执行自动化;客户端则由测试作者驱动,负责通过网络向服务器发送命令并接收响应。本指南以 Appium 客户端简介 为核心,结合本仓库中@appium/base-driver的协议路由源码与sample-code中的多语言示例,系统讲解客户端的概念模型、HTTP 协议层工作原理、五种主流语言的客户端用法以及如何挑选和维护合适的客户端库。
一、客户端在 Appium 架构中的位置
Appium 采用客户端-服务器架构,这与它在 Appium 如何工作 中"允许从任何编程语言轻松访问统一 API"的目标直接相关。两个角色的分工如下:
- 服务器端(Server):由 Appium 本身以及您为自动化任务安装的任何驱动程序(Driver)和插件(Plugin)组成。它连接到被测设备(模拟器、真机或云设备),并实际负责在这些设备上执行自动化。
- 客户端(Client):由您(Appium 测试作者)驱动,负责通过网络向服务器发送命令,并接收来自服务器的响应。这些响应既可以用来判断自动化命令是否成功,也可能包含您查询到的应用程序状态信息。
也就是说,所有"困难的部分"——如何在一个给定平台上实现自动化——都被收敛在服务器端一次性处理;而客户端只需要是"瘦"的库,以适合该语言的方式把对服务器的 HTTP 请求编码出来即可。也正因为这种解耦,Appium 服务器与 Appium 客户端不需要运行在同一台机器上,只要两者之间存在可用的网络即可,这也是云测试提供商得以托管 Appium 服务器、而您只需将客户端脚本指向其安全端点的基础。
关于服务器端的更多细节(即"Appium 究竟如何控制设备"),请参阅 Appium 驱动程序介绍。
二、自动化命令本质上是 HTTP API
一个会话中到底有哪些自动化命令可用?这取决于您在本次会话中使用的特定驱动程序和插件。一组标准的命令通常包括:
- 查找元素(Find Element)
- 点击元素(Click Element)
- 获取页面源代码(Get Page Source)
- 截取屏幕截图(Take Screenshot)
如果您查阅 WebDriver 规范,会发现这些命令不是以任何特定编程语言定义的——它们不是 Java 命令、JavaScript 命令或 Python 命令,而是一个可以从任何编程语言(甚至不用编程语言,直接用 cURL)访问的 HTTP API。
以Find Element(查找元素)命令为例,它对应发送到 HTTP 端点/session/:sessionid/element的POST请求,其中:sessionid是服务器在之前Create Session(创建会话)调用中生成的唯一会话 ID 的占位符。
2.1 源码佐证:路由定义与必填参数
这一端点定义并非空谈,在 w3c.ts 路由表 中有完整实现:
// packages/base-driver/lib/protocol/routes/w3c.ts '/session/:sessionId/element': { POST: { command: 'findElement', payloadParams: {required: ['using', 'value']}, }, },从源码可以看到两个关键事实:
- 命令到方法名的映射:HTTP 端点
/session/:sessionId/element的POST请求被映射到findElement这个命令名(最终由驱动程序中同名的方法实现)。驱动程序正是通过@appium/base-driver中的这套路由表来确定"协议命令 ↔ Node.js 方法名"的对应关系,并声明命令所需参数。 - 必填参数:
findElement命令要求请求体必须携带using与value两个参数——using指明查找策略(例如xpath),value则是具体的查询表达式。这正是后文示例中find_element(by=By.XPATH, value='//*[@text="Foo"]')调用形式的协议层根源。
同理,jsonwp.ts 路由表 中还保留了兼容旧 JSON Wire Protocol 的端点/session/:sessionId/element/:elementId,用于按元素 ID 继续操作元素。
这些协议层面的知识主要对开发与 WebDriver 规范配套技术(例如编写客户端库、调试协议流量)的人有用。对于绝大多数编写 Appium/Selenium 测试的开发者来说,真正打交道的是下一节介绍的"客户端库"。
三、为什么需要客户端库
对普通测试作者而言,手动拼写 HTTP 请求毫无吸引力。当您编写 Appium 测试时,您希望使用自己熟悉的编程语言。幸运的是,存在一组 Appium 客户端库,它们承担了与 Appium 服务器进行 HTTP 通信的全部责任,同时为特定编程语言暴露一组"原生"命令——对测试作者来说,就像在直接编写 Python、JavaScript 或 Java 代码一样自然。
这些库在 Appium 生态中有多种称呼,含义完全相同:
- "客户端"(client)
- "客户端库"(client library)
- "客户端绑定"(client binding)
四、同一命令集在五种语言中的写法
以下是使用各语言推荐的 Appium 客户端绑定,在五种不同编程语言中实现同一套命令序列的示例。注意这不是包含全部导入语句的可直接运行代码,完整的安装与命令参考请查阅各客户端库的文档。
=== "JavaScript(WebdriverIO)"
const element = await driver.$('//*[@text="Foo"]'); await element.click(); console.log(await element.getText()) console.log(await driver.getPageSource())=== "Java"
WebElement element = driver.findElement(By.Xpath("//*[@text='Foo']")) element.click() System.out.println(element.getText()) System.out.println(driver.getPageSource())=== "Python"
element = driver.find_element(by=By.XPATH, value='//*[@text="Foo"]') element.click() print(element.text) print(driver.page_source)=== "Ruby"
element = driver.find_element :xpath, '//*[@text="Foo"]' element.click puts element.text puts driver.page_source=== "C#"
AppiumElement element = driver.FindElement(MobileBy.AccessibilityId("Views")); element.click(); System.Console.WriteLine(element.Text); System.Console.WriteLine(driver.PageSource);4.1 这些脚本在底层做的是同一件事
尽管语言不同、API 风格各异,上述五个脚本在协议层面完成的工作完全一致:
- 调用
Find Element(查找元素):using参数值为xpath,value参数表达用于查找元素的 XPath 查询表达式(例如//*[@text="Foo"]表示查找文本为 "Foo" 的任意元素)。 - 使用上一步返回的元素 ID 调用
Click Element(点击元素)。 - 使用同一元素的 ID 调用
Get Element Text(获取元素文本),并打印到控制台。 - 调用
Get Page Source(获取页面源代码)检索页面/应用源码并打印到控制台。
也就是说:无论客户端 API 长成什么样子,最终都会转化为对 WebDriver HTTP 端点的调用——点击元素对应POST /session/:sessionId/element/:elementId/click,获取元素文本对应GET /session/:sessionId/element/:elementId/text,这些端点同样定义在 w3c.ts 路由表中。
4.2 本仓库中的完整可运行示例
上述代码段为了聚焦命令调用而省略了连接建立、能力(Capabilities)配置等上下文。如果您想看到真正可运行的版本,本仓库的 sample-code/quickstarts 提供了 JavaScript、Python、Ruby 三种语言的完整快速入门脚本。以 Python 为例:
# packages/appium/sample-code/quickstarts/py/test.py import unittest from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumBy capabilities = dict( platformName='Android', automationName='uiautomator2', deviceName='Android', appPackage='com.android.settings', appActivity='.Settings', language='en', locale='US' ) appium_server_url = 'http://localhost:4723' class TestAppium(unittest.TestCase): def setUp(self) -> None: self.driver = webdriver.Remote(appium_server_url, options=UiAutomator2Options().load_capabilities(capabilities)) def tearDown(self) -> None: if self.driver: self.driver.quit() def test_find_apps(self) -> None: el = self.driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Apps"]') el.click()JavaScript(WebdriverIO)版本则显式展示了客户端如何定位 Appium 服务器,默认连接本机4723端口(可通过环境变量覆盖):
// packages/appium/sample-code/quickstarts/js/test.js const wdOpts = { hostname: process.env.APPIUM_HOST || 'localhost', port: parseInt(process.env.APPIUM_PORT, 10) || 4723, logLevel: 'info', capabilities, };Ruby 版本使用Appium::Core.for构建核心客户端并start_driver启动会话,同样指向http://localhost:4723(见 test.rb)。
各语言的官方快速入门文档还可在仓库中找到,例如 test-js、test-py、test-java、test-rb、test-dotnet。
五、选择客户端前必须知道的事
在挑选或使用某个客户端之前,有一个容易忽视却很重要的前提:每个客户端都是独立维护的。这带来几个实际影响:
- 某个功能在一个客户端中可用,并不代表在另一个客户端中也可用——不过所有客户端都至少支持标准的 W3C 协议,以及常见的 Appium 扩展命令。
- 某个客户端拥有一套好用的辅助函数,另一个客户端不一定有。
- 不同客户端的更新频率差异很大:有的维护非常活跃,有的则不然。
因此,选择客户端库时应按优先级考虑两个因素:
- 您想使用的编程语言——这是首要考虑因素;
- 该库的功能完善程度与维护状况——这决定您能获得多少 Appium 扩展能力、能否及时跟进新版本。
5.1 官方客户端一览
由 Appium 团队当前维护的官方客户端(完整列表见 客户端列表)包括:
| 客户端 | 语言 | 安装方式(仓库文档示例) |
|---|---|---|
| Java Client | Java | Maven:io.appium:java-client(<scope>test</scope>);Gradle:testImplementation 'io.appium:java-client:版本号' |
| Python Client | Python | pip install Appium-Python-Client |
| Ruby Core Client | Ruby | gem install appium_lib_core(推荐) |
| Ruby Client | Ruby | gem install appium_lib(基于 Ruby Core 的封装,含若干辅助方法,但可能引入额外复杂度,因此官方更推荐 Ruby Core) |
| .NET Client | C# | dotnet add package Appium.WebDriver |
此外还有社区维护的其他语言客户端(如 WebdriverIO、Nightwatch.js、RobotFramework AppiumLibrary、Rust 的 appium-client、SwiftAppium 等)。原则上,任何符合 W3C WebDriver 规范的客户端都能与 Appium 良好集成,但一些 Appium 特有的命令可能未在其他客户端中实现。
六、如何学习使用一个客户端
要学习某个 Appium 客户端的具体用法,请访问该客户端的主页获取文档。这里有一个常见的认知盲区需要特别留意:
在许多情况下,特定语言的 Appium 客户端是构建在Selenium客户端之上的,因此某些 Appium 客户端可能只记录它在 Selenium 客户端基础上新增的功能。
这意味着要获得完整的参考,您可能需要同时查阅两份文档:
- Appium 客户端文档——了解 Appium 特有的能力(移动端定位策略、触摸操作、会话管理等);
- 底层 Selenium 客户端文档——了解标准 WebDriver 命令(元素查找、等待、页面导航等通用能力)。
因为 Appium 客户端继承了 Selenium 的技术遗产,这种"叠加"关系在 Java、Python、Ruby、.NET 等生态中非常普遍。理解了这一点,您在排查"某个方法为什么在客户端文档里找不到"之类的问题时会轻松很多。
七、小结
客户端是 Appium 架构中与测试作者距离最近的一环:它屏蔽了 WebDriver 协议的所有 HTTP 细节,把/session/:sessionid/element这样的端点调用翻译成您熟悉语言里的一个方法调用。回顾本篇的核心结论:
- Appium 是客户端-服务器架构,服务器负责在设备上执行自动化,客户端负责发送命令与接收响应;
- 所有自动化命令本质上是 HTTP API 调用,
findElement等命令与端点的映射关系可在 w3c.ts 中查看; - 客户端库让测试作者可以用自己熟悉的语言编写测试,同一命令集在五种主流语言中的写法已在上文逐一对比;
- 选择客户端时,先考虑语言,再考虑功能完备性与维护活跃度;
- 官方维护的客户端列表与安装方式,请前往 客户端列表 页面查看。
这就是关于 Appium 客户端你需要知道的全部内容——现在可以挑选适合您的客户端,开始编写第一条自动化测试了。
【免费下载链接】appiumCross-platform automation framework for all kinds of apps, built on top of the W3C WebDriver protocol项目地址: https://gitcode.com/GitHub_Trending/ap/appium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考