手势操作
通过上一章节的学习,我们已经掌握了编写脚本的基本技巧,接下来我们要通过本章节的学习做一个有意思的手势解锁,如果时间充足,可以尝试针对地图类APP来实践一下本节课内容。 预备知识:手机屏幕二维坐标系
你平时都使用过什么手势?
聊起这个话题,相信你们在日常使用手机中都是有使用过如下的手势
上下左右滑屏(慢速)
快速滑动
滚动(滚动和滑动有什么区别?
)
放大缩某个控件
相信大多数时间我们所使用的手势都是滑动,因为大多数APP基本都有滑动的手势, 比如安装好的APP出现引导页,列表内容单页不够显示,而滑动是一个比较友好的方式。 这样我们在自动化APP的时候就会遇到很多种滑动的情况,接下来让我们深入的了解一下这些手势。
appium中提供的手势
Java client 默认提供的API
- swipe --- 滑动
- zoom --- 放大
- pinch ---缩小
- tap --- 点点(请思考tap和click的区别?)
- scroll ----滚动
swipe方法详解
滑动和滚动的区别你想清楚了吗?
首先让我们了解一下appium 自带的滑动方法swipe,swipe方法的定义如下:
public void swipe(int startx,
int starty,
int endx,
int endy,
int duration)
swipe方法共有五个参数,其中参数依次代表起始点x、y坐标,终点x、y坐标和滑动时间,单位毫秒。 如果想滑的快,就把时间设置小,反之。
swipe方法的本质是封装TouchAction,通过touchAction先按下起始点坐标,再间隔时间之后移动到终点坐标并释放。
具体实现方法如下:
TouchAction touchAction = new TouchAction(this);
// appium converts press-wait-moveto-release to a swipe action
touchAction.press(startx, starty).waitAction(duration)
.moveTo(endx, endy).release();
touchAction.perform();
提示:swipe 的高级用法,swipe 可以进一步封装,比如一些MobileElement需要滑动屏幕才能出现,这个时候就可以封装一个滚动到这些MoblieElement出现为止的方法。
zoom方法详解
通过了解swipe方法实际上zoom方法也类似 首先看一下该方法的定义:
void zoom(WebElement el);
void zoom(int x, int y);
zoom方法有两个,一个是传入一个WebElement,另外一个传入起始点坐标
zoom(x,y) 方法其实是由两个 MultiTouchAction实现的 首先根据你传入的坐标点确定偏移量,然后创建两个Action分别相反方向移动,同时间释放。
MultiTouchAction multiTouch = new MultiTouchAction(this);
int scrHeight = manage().window().getSize().getHeight();
int yOffset = 100;
if (y - 100 < 0) {
yOffset = y;
} else if (y + 100 > scrHeight) {
yOffset = scrHeight - y;
}
TouchAction action0 = new TouchAction(this).press(x, y).moveTo(x, y - yOffset).release();
TouchAction action1 = new TouchAction(this).press(x, y).moveTo(x, y + yOffset).release();
multiTouch.add(action0).add(action1);
multiTouch.perform();
另外一个zoom方法也类似,可自己研究一下。
pinch方法详解
pinch 方法做的事情个zoom刚好相反但使用方法是一样的
void pinch(WebElement el);
void pinch(int x, int y);
tap方法详解
之前有提到过一个问题,tap和click的行为到底有什么不同? 对于tap单一finger操作除了和click是通用的,但如不止一个finger那就不同咯。
先看一下tap方法
void tap(int fingers, int x, int y, int duration);
void tap(int fingers, WebElement element, int duration);
第一个的使用方法传入finger和要tap的坐标点还有间隔时间
第二个的使用方法是传finger和要tap的对象还有间隔时间
tap方法的实现代码如下:
MultiTouchAction multiTouch = new MultiTouchAction(this);
for (int i = 0; i < fingers; i++) {
multiTouch.add(createTap(x, y, duration));
}
multiTouch.perform();
scroll方法详解
scroll是一个抽象的方法,iOS和Android各自实现
scrollTo(String text)
scrollToExact(String text)
那么问题就来了,这两者有什么样的区别?
首先两者传入的都是字符串,而这个字符串是对所要滚动到的对象的描述,不同之处在于scrollTo是包含contains,而scrollToExact是equals,精确匹配。
提示:scroll可以滚动到查找某个MobileElement出现,和swipe不同的是这个滚动只能是当前屏幕,不能跨页面
自定义手势
注意在早期的Appium版本中,可使用mobile command 自定一些手势,比如swipe,flick 但是在最近的Appium中已经不再支持这些mobile commandTried to execute non-existent mobile command 'swipe'. Most mobile commands have been ported to official client library methods. Please check your Appium library for more information and documentation
如果你在网上看到类似这样的代码,切记已经完全无效:
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> swipeObject = new HashMap<String, String>();
swipeObject.put("startX", "100");
swipeObject.put("startY", "400");
swipeObject.put("endX", "100");
swipeObject.put("endY", "200");
swipeObject.put("duration", "400");
js.executeScript("mobile: swipe", swipeObject);
而这里我讲的自定义手势,比如向上向下滑动,是根据swipe的原理设计出来的
还可以进一步封装滑动到某MobleElement 出现 举个例子,向上滑动屏幕 :
/**
* This Method for swipe up
*
* @author Young
* @param driver
* @param during
*/
public void swipeToUp(AndroidDriver<MobileElement> driver, int during)
{
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, during);
}
首先获取你设备的宽度和高度,然后根据二维坐标系进行滑动,同理你可以试着封装一个手势。
一个手势解锁的demo
核心代码如下:
@Test
public void GustureLockerTest() throws InterruptedException
{
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
MobileElement button = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"设置手势密码\")");
button.tap(1, 1000);
// get all the items of gesture locker
List<MobileElement> items = driver.findElementsByClassName("android.widget.ImageView");
for (MobileElement item : items)
{
/**
* 0 1 2 3 4 5 6 7 8
*/
item.click();
}
// create a Z from 0->1->2->4->6->7->8
TouchAction touches = new TouchAction(driver);
touches.press(items.get(0)).waitAction(1000).moveTo(items.get(1)).waitAction(1000).moveTo(items.get(2))
.waitAction(1000).moveTo(items.get(4)).moveTo(items.get(6)).waitAction(1000).moveTo(items.get(7))
.waitAction(1000).moveTo(items.get(8)).release();
touches.perform();
Thread.sleep(1000);
touches.press(items.get(0)).waitAction(1000).moveTo(items.get(1)).waitAction(1000).moveTo(items.get(2))
.waitAction(1000).moveTo(items.get(4)).release();
touches.perform();
Assert.assertTrue(driver.findElementByName("与上一次绘制不一致,请重新绘制").isDisplayed());
}
总结
本章我们都学习了常见手势的使用方法,其中appium自带的
- swipe
- tap
- zoom
- pinch
- scroll
掌握了这些,可以针对一个地图类型的app实践一下
@Test
public void GustureLockerTest() throws InterruptedException
{
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
Thread.sleep(15000);
// swipe to right
driver.swipe(width / 4, height / 2, width * 3 / 4, height / 2, 300);
// swipe to left
driver.swipe(width * 3 / 4, height / 2, width / 4, height / 2, 300);
Thread.sleep(5000);
driver.pinch(width / 4, height / 4);
Thread.sleep(5000);
driver.zoom(width / 4, height / 4);
Thread.sleep(5000);
// tap
driver.tap(2, width / 2, height / 2, 1000);
}
该app的下载地址:
https://github.com/tobecrazy/LuoHe/raw/master/app/build/outputs/apk/app-debug.apk
相关资料
demo所使用的APK
https://github.com/tobecrazy/appiumDemo/raw/master/apps/Locker.apk