## 使用 WebDriverAgent/XCTest Backend 进行iOS自动化手势操作
很可惜,苹果官方的 XCTest 框架本身并不支持 TouchAction 接口实现的 W3C 标准。尽管如此,XCTest 提供了非常丰富的手势操作,这些操作都是 iOS 平台独有的。你可以在 1.6.4-beta 版本的 Appium 中开始使用这些手势操作。
需要特别注意的是目前XCTest和WDA正在不断优化改变的阶段,这意味着所有 `mobile: *` 的命令可能会在没任何通知的情况下就被调整更改。
### mobile: swipe
这个手势是在指定的屏幕上的控件或App的控件上执行“滑动”操作,一般是针对整个屏幕。这个方法不支持通过坐标来操作,并且仅仅是简单的模拟单个手指滑动。这个方法对于诸如相册分页、切换视图等情况可能会发挥比较大的作用。更复杂的场景可能需要用到`mobile:dragFromToForDuration`,这个方法支持传坐标(coordinates )和滑动持续时间(duration)。
#### 支持参数
* _direction_: 'up', 'down', 'left' or 'right'. 这4个参数是固定的。
* _element_: 需要滑动的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
#### 用法示例
```java
// Java
JavascriptExecutor js = (JavascriptExecutor) driver;
Map<String, Object> params = new HashMap<>();
scrollObject.put("direction", "down");
scrollObject.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: swipe", params);
```
### mobile: scroll
滚动元素或整个屏幕。支持不同的滚动策略。该方法提供了4个可选择滑动策略:按照顺序有“name”,“direction”,“predicateString”或“toVisible”。所有的滑动策略都是排他性的,一次滑动只能选择一个策略。你可以使用`mobile:scroll`来对表格中或者集合视图中的某个已知控件进行精确的滚动操作。然而目前有一个已知的局限问题:如果需要在父容器上执行太多的滚动手势到达指定的某个子元素(几十个子元素),则方法调用可能会失败。
#### 支持参数
* _element_: 需要滚动的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
* _name_: 需要执行滚动的子控件的`accessibility id`。
将`predicateString`参数设置为`“name == accessibilityId”`可以实现相同的结果。如果`element`不是容器,则不起作用。
* _direction_: 'up', 'down', 'left' or 'right'. 该参数与`swipe`中的比,差别在于`scroll`会尝试将当前界面完全移动到下一页。(`page`一词表示单个设备屏幕中的所有内容)
* _predicateString_: 需要被执行滚动操作的子控件的NSPredicate定位器。如果控件不是容器,则不起作用。
* _toVisible_: 布尔类型的参数。如果设置为`true`,则表示要求滚动到父控件中的第一个可见到的子控件。如果`element`未设置,则不生效。
#### 用法示例
```python
# Python
driver.execute_script('mobile: scroll', {'direction': 'down'});
```
### mobile: pinch
在给定的控件或应用程序控件上执行捏合手势。
#### 支持参数
* _element_: 需要捏合的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
* _scale_: 浮动型夹点尺度。使用0和1之间的比例来“捏紧”或缩小,大于1的比例“撑开”或放大。强制参数
* _velocity_: 每秒缩放速度(浮点值)。强制参数
#### 用法示例
```ruby
# Ruby
execute_script 'mobile: pinch', scale: 0.5, velocity: 1.1, element: element.ref
```
### mobile: doubleTap
在指定控件上或屏幕上执行双击手势。
#### 支持参数
* _element_: 需要双击的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
* _x_: 屏幕x轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
* _y_: 屏幕y轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
#### 用法示例
```javascript
// javascript
driver.execute('mobile: doubleTap', {element: element.value.ELEMENT});
```
### mobile: touchAndHold
在指定控件或屏幕上长按的手势操作。
#### 支持参数
* _element_: 需要长按的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
* _duration_: 长按的持续时间(秒),浮点型。强制性参数
* _x_: 屏幕x轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
* _y_: 屏幕y轴坐标点,浮点型. 仅当`element`未设置时才是强制参数
#### 用法示例
```csharp
// c#
Dictionary<string, object> tfLongTap = new Dictionary<string, object>();
tfLongTap.Add("element", element.Id);
tfLongTap.Add("duration", 2.0);
((IJavaScriptExecutor)driver).ExecuteScript("mobile: touchAndHold", tfLongTap);
```
### mobile: twoFingerTap
在给定元素或应用程序元素上执行两个手指点击手势。
#### 支持参数
* _element_: 需要两只手指操作的控件ID(作为十六进制哈希字符串)。如果没有提供该参数的话,则会使用App的控件作为替代。
#### 用法示例
```csharp
// c#
Dictionary<string, object> tfTap = new Dictionary<string, object>();
tfTap.Add("element", element.Id);
((IJavaScriptExecutor)driver).ExecuteScript("mobile: twoFingerTap", tfTap);
```
### mobile: tap
在指定控件或屏幕上的坐标执行点击手势。
#### 支持参数
* _element_: 控件ID(作为十六进制哈希字符串)。 如果设置 了`element`参数,则`x`、`y`代表的是以当前`element`为边界的xy轴。若未设置,则`x`,`y`代表的是以手机屏幕为边界。
* _x_: x轴坐标,类型为float。强制参数
* _y_: y轴坐标,类型为float。强制参数
#### 案例
```php
// PHP
$params = array(array('x' => 100.0, 'y' => 50.0, 'element' => element.GetAttribute("id")));
$driver->executeScript("mobile: tap", $params);
```
### mobile: dragFromToForDuration
通过坐标点执行拖放手势。可以在控件上执行,也可以在屏幕上执行。
#### Supported arguments
* _element_: 控件ID(作为十六进制哈希字符串)。 如果设置 了`element`参数,则`x`、`y`代表的是以当前`element`为边界的xy轴。若未设置,则`x`,`y`代表的是以手机屏幕为边界。
* _duration_: 浮点数范围[0.5,60]。表示开始拖动点之前的点击手势需要多长时间才能开始拖动。强制参数
* _fromX_: 起始拖动点的x坐标(类型float)。强制参数
* _fromY_: 起始拖动点的y坐标(类型float)。强制参数
* _toX_: 结束拖曳点的x坐标(float类型)。强制参数
* _toY_: 结束拖动点的y坐标(类型float)。强制参数
#### 用法示例
```java
// Java
JavascriptExecutor js = (JavascriptExecutor) driver;
Map<String, Object> params = new HashMap<>();
params.put("duration", 1.0);
params.put("fromX", 100);
params.put("fromY", 100);
params.put("toX", 200);
params.put("toY", 200);
params.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: dragFromToForDuration", params);
```
### mobile: selectPickerWheelValue
选择下一个或上一个picker wheel的值。 如果这些值是动态的,那么这个方法是能起作用的。XCTest有一个BUG,就是你并不能知道要选择哪一个,或者当前的选择区域是否生效。
#### 支持参数
* _element_: PickerWheel的内部元素id(作为十六进制哈希字符串)执行值选择。元素必须是XCUIElementTypePickerWheel类型。强制参数
* _order_: `next` 选择下一个value,`previous`选择前面一个value。强制参数
* _offset_: 区间值: [0.01, 0.5]。它定义了picker wheel的中心距离应该有多远。 通过将该值乘以实际的picker wheel高度来确定实际距离。太小的偏移值可能不会改变picker wheel的值,而过高的值可能会导致picker wheel同时切换两个或多个值。通常最优值位于范围[0.15,0.3]中。默认为0.2
#### 用法示例
```java
// Java
JavascriptExecutor js = (JavascriptExecutor) driver;
Map<String, Object> params = new HashMap<>();
params.put("order", "next");
params.put("offset", 0.15);
params.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: selectPickerWheelValue", params);
```
### mobile: alert
对NSAlert实例执行操作。
#### 支持参数
* _action_: 支持以下操作: `accept`, `dismiss` and `getButtons`。强制参数
* _buttonLabel_: 点击已有警报按钮的标签文本。这是一个可选参数,只能与`accept`和`dismiss` 操作相结合才有效。
#### 用法示例
```python
# Python
driver.execute_script('mobile: alert', {'action': 'accept', 'buttonLabel': 'My Cool Alert Button'});
```
### mobile: tapWithNumberOfTaps
从Appium 1.17.1.开始,对单个或者多个接触点,点击一次或者多次。
#### 支持参数
* _element_: 要执行一次或多次点击的内部元素标识符(用十六进制字符串表示)
* _numberOfTaps_: 点击次数
* _numberOfTouches_: 接触点数量
#### 用法示例
```ruby
# Ruby
e = @driver.find_element :id, 'target element'
# Taps the element with a single touch point twice
@driver.execute_script 'mobile: tapWithNumberOfTaps', {element: e.ref, numberOfTaps: 2, numberOfTouches: 1}
```
#### 参考
[tapWithNumberOfTaps:numberOfTouches:](https://developer.apple.com/documentation/xctest/xcuielement/1618671-tapwithnumberoftaps)
### 进阶主题
查看 [WDA Element Commands API](https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m)
以获取有关在Facebook WebDriverAgent中实现的手势的信息。
XCTest文档列出了关于[XCUIElement](https://developer.apple.com/documentation/xctest/xcuielement)和[XCUICoordinate](https://developer.apple.com/documentation/xctest/xcuicoordinate)方法所有可用手势的信息。
本文由 [大东](https://testerhome.com/Anikikun) 翻译,由 [lihuazhang](https://github.com/lihuazhang) 校验。
- 关于TesterHome和MTSC
- 关于Appium
- 简介
- Appium 客户端
- 入门指南
- 已支持的平台
- API 文档
- Appium驱动
- XCUITest (iOS)
- XCUITest Real Devices (iOS)
- UIAutomation (iOS)
- UIAutomation Safari Launcher (iOS)
- UIAutomator (Android)
- UIAutomator2 (Android)
- Espresso (Android)
- Windows
- Mac
- Appium命令
- Status
- Execute Mobile Command
- Session
- Create
- End
- Get Session Capabilities
- Go Back
- Screenshot
- Source
- Timeouts
- Timeouts
- Implicit Wait
- Async Script
- Orientation
- Get Orientation
- Set Orientation
- Geolocation
- Get Geolocation
- Set Geolocation
- Logs
- Get Log Types
- Get Logs
- Events
- Log event
- Get events
- Settings
- Update Settings
- Get Device Settings
- Settings
- Update Settings
- Get Device Settings
- Execute Driver Script
- Device
- Activity
- Start Activity
- Current Activity
- Current Package
- App
- Install App
- Is App Installed
- Launch App
- Background App
- Close App
- Reset App
- Remove App
- Activate App
- Terminate App
- Get App State
- Get App Strings
- End Test Coverage
- Clipboard
- Get Clipboard
- Set Clipboard
- Emulator
- Power AC
- Power Capacity
- Files
- Push File
- Pull File
- Pull Folder
- Interactions
- Shake
- Lock
- Unlock
- Is Locked
- Rotate
- Keys
- Press keycode
- Long press keycode
- Hide Keyboard
- Is Keyboard Shown
- Network
- Toggle Airplane Mode
- Toggle Data
- Toggle WiFi
- Toggle Location Services
- Send SMS
- GSM Call
- GSM Signal
- GSM Voice
- Network Speed
- Performance Data
- Get Performance Data
- Performance Data Types
- Screen Recording
- Start Screen Recording
- Stop Screen Recording
- Simulator
- Perform Touch ID
- Toggle Touch ID Enrollment
- System
- Open Notifications
- System Bars
- System Time
- Display density
- Authentication
- Finger Print
- Element
- Find Element
- Find Elements
- Actions
- Click
- Send Keys
- Clear
- Attributes
- Text
- Name
- Attribute
- Selected
- Enabled
- Displayed
- Location
- Size
- Rect
- CSS Property
- Location in View
- Other
- Submit
- Active Element
- Equals Element
- Context
- Get Context
- Get All Contexts
- Set Context
- Interactions
- Mouse
- Move To
- Click
- Double Click
- Button Down
- Button Up
- Touch
- Single Tap
- Double Tap
- Move
- Touch Down
- Touch Up
- Long Press
- Scroll
- Flick
- Multi Touch Perform
- Touch Perform
- W3C Actions
- Web
- Window
- Set Window
- Close Window
- Get Handle
- Get Handles
- Get Title
- Get Window Size
- Set Window Size
- Get Window Position
- Set Window Position
- Maximize Window
- Navigation
- Go to URL
- Get URL
- Back
- Forward
- Refresh
- Storage
- Get All Cookies
- Set Cookie
- Delete Cookie
- Delete All Cookies
- Frame
- Switch to Frame
- Switch to Parent Frame
- Execute Async
- Execute
- 编写 & 运行Appium脚本
- Running Tests
- Desired Capabilities
- The --default-capabilities flag
- Finding Elements
- Touch Actions
- CLI Arguments
- Server Security
- Web/Web Views
- Mobile Web Testing
- Automating Hybrid Apps
- Using ios-webkit-debug-proxy
- Using Chromedriver
- Image Comparison
- iOS
- Low-Level Insights on iOS Input Events
- XCUITest Mobile Gestures
- XCUITest Mobile App Management
- iOS Pasteboard Guide
- iOS Predicate Guide
- iOS Touch ID Guide
- iOS Install Certificate
- tvOS support
- Pushing/Pulling files
- Audio Capture
- Android
- Low-Level Insights on Android Input Events
- UiSelector Guide
- Espresso Datamatcher Guide
- Android Code Coverage Guide
- Activities Startup Troubleshooting Guide
- How To Execute Shell Commands On The Remote Device
- Android Device Screen Streaming
- How To Emulate IME Actions Generation
- How To Test Android App Bundle
- Other
- Reset Strategies
- Network Connection Guide
- Using Unicode with Appium
- Troubleshooting
- Tutorial
- Swipe Tutorial
- Screen
- Element
- Partial screen
- Simple
- Multiple scroll views
- Add scroll layout
- Tricks and Tips
- Screen
- Element
- Element search
- Fast
- Slow
- Guide
- 进阶概念
- 定位图像中的元素
- 使用定位元素的插件
- 迁移到 XCUITest
- 在 Appium 中使用 Selenium Grid
- Appium Logs Filtering
- 跨域 iframes
- 使用自定义 WDA 服务器
- 使用不同版本的 Xcode 运行
- The Event Timings API
- 并行测试的设置
- The Settings API
- Memory Collection
- 向Appium项目做贡献
- 从源代码运行 Appium
- 开发者概述
- 标准开发命令
- Appium 风格指南
- 如何编写文档
- Appium 包结构
- 鸣谢