Appium 与 WebDriver

运行 droidline webdriver,并把 Appium 客户端指向它。用 Python、Java、JavaScript 等语言写的现有 Appium 脚本可以不经 ADB,通过 Droidline 控制手机。

本页为译文。如与英文版不一致,以英文版为准。 English

droidline webdriver 支持 W3C WebDriver 协议以及 Appium 的 Android 扩展。把 Appium 客户端指向它,为 Appium 编写的脚本就会通过 Droidline 控制手机:定位方式和元素命令相同,不需要 ADB,也不需要 Appium 服务器。

这是可选功能,只在命令运行期间工作。你的 Droidline 脚本不需要它。

启动

Droidline 服务器需要正在运行。在另一个终端中运行:

droidline webdriver
WebDriver bridge on http://127.0.0.1:4723
Use it as the Appium server URL. Stop with Ctrl+C.

客户端要求填写 Appium 服务器地址时,使用 http://127.0.0.1:4723。--listen 用来选择其他地址;请保持为 127.0.0.1,因为桥接没有密码。

连接

# pip install Appium-Python-Client
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy

opts = UiAutomator2Options()
opts.set_capability("appium:udid", "shelf-01")
opts.set_capability("appium:appPackage", "com.android.settings")
d = webdriver.Remote("http://127.0.0.1:4723", options=opts)

d.find_element(AppiumBy.XPATH, "//*[@text='网络和互联网']").click()
d.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("WLAN")')
d.quit()
import { remote } from "webdriverio";

const d = await remote({
  hostname: "127.0.0.1",
  port: 4723,
  capabilities: { platformName: "Android", "appium:udid": "shelf-01" },
});
await d.$("~更多选项").click();
await d.deleteSession();

上面的 Appium Python 客户端已经在真机上通过这个桥接测试过。WebdriverIO、Java 和 .NET 客户端、Robot Framework 的 AppiumLibrary、Appium Inspector 等使用同一协议的其他客户端也以相同方式连接。客户端发送桥接不支持的命令时,它会回复 unknown command 并给出命令名称。

Capability

Capability作用
platformNameAndroid,或者省略。
appium:udid 或 droidline:device手机的 ID 或名称。不指定时使用唯一在线的手机。
appium:deviceName只有当某部已配对手机正好是这个名称或 ID 时才使用,其他值都会被忽略。
appium:appPackage、appium:appActivity启动这个应用。不会重置,也不会清除数据;mobile: clearApp 只在设备所有者模式下清除应用数据。
appium:newCommandTimeout这么多秒内没有命令就结束会话。默认 60,0 表示永不结束。
droidline:leasetrue 会在会话期间租用一部空闲手机,会话结束时归还。

定位方式

方式匹配
xpath在页面源码上执行 XPath,标签和属性与 UiAutomator2 相同(@text、@resource-id、@content-desc、@class、@bounds 以及各状态值)。
idresource-id,完整的或只写 :id/ 之后的名称。
accessibility idcontent-desc。
class name类名,例如 android.widget.Button。
-android uiautomatornew UiSelector() 的 text、textContains、textStartsWith、textMatches、description 及其变体、resourceId、className、packageName、各状态值、instance、childSelector 和 fromParent,以及 new UiScrollable(...).scrollIntoView(...) 和 scrollTextIntoView(...)。
-droidline query以 JSON 书写的 Droidline 查询,例如 {"class":"android.widget.Switch","row":{"text":"WLAN"}}。
nametext。

用 implicitly_wait 设置的隐式等待适用于所有方式;与 WebDriver 一样,设置之前为 0。

支持的功能

  • 元素:查找一个或多个,也可以在另一个元素内部查找;click、send_keys、clear、text、get_attribute、rect、is_displayed、is_enabled、is_selected 以及元素截图。已经离开屏幕的元素会引发 stale element 错误。
  • 页面源码、截图和窗口尺寸。
  • 单指 W3C actions:点击、长按和滑动。key actions 可以输入文字,并按下 Enter、Backspace 和 Tab;Escape 会按下返回键。
  • 应用和设备调用:activate_app、query_app_state、press_keycode、hide_keyboard、is_keyboard_shown、current_activity、current_package、open_notifications、lock、unlock。
  • 脚本:mobile: clearApp(仅限设备所有者模式)、mobile: activateApp、mobile: pressKey、mobile: clickGesture、mobile: longClickGesture,以及能运行任意 Droidline 命令的 mobile: droidline:
d.execute_script("mobile: droidline", {"cmd": "wait_idle"})
d.execute_script("mobile: droidline", {"cmd": "proxy_check"})

与 Appium 的不同

Droidline 不使用 ADB,所以需要 ADB 的功能都没有:安装和卸载应用、mobile: shell、推送和拉取文件、logcat 以及 WEBVIEW 上下文。此外:

  • send_keys 会替换输入框中的文字,与 Droidline 的 input 相同。
  • 手势只用一根手指;多点触控 actions 会失败。
  • appium:noReset 和 appium:fullReset 会被忽略。桥接从不自行清除数据。
  • terminate_app 和 mobile: terminateApp 会返回 unsupported operation 错误。要强行停止应用,请使用设置应用示例。
  • mobile: clearApp 运行的是 clear_data,所以只在设备所有者模式下可用。