ADB 在APP自动化测试应用汇总

##ADB模拟按键操作

模拟点击
adb shell input tap posX posY

模拟滑动
adb shell input swipe posX1 posY1 posX2 posY2 scrollTime

在屏幕上做划屏操作,前四个数为坐标点,后面是滑动的时间(单位毫秒)

输入文本
adb shell input text string

模拟按键
adb shell input keyevent keycode

其中keycode的对应表如下:

keycode num
KEYCODE_UNKNOWN 0
KEYCODE_MENU 1
KEYCODE_SOFT_RIGHT 2
KEYCODE_HOME 3
KEYCODE_BACK 4
KEYCODE_CALL 5
KEYCODE_ENDCALL 6
KEYCODE_0 7
KEYCODE_1 8
KEYCODE_2 9
KEYCODE_3 10
KEYCODE_4 11
KEYCODE_5 12
KEYCODE_6 13
KEYCODE_7 14
KEYCODE_8 15
KEYCODE_9 16
KEYCODE_STAR 17
KEYCODE_POUND 18
KEYCODE_DPAD_UP 19
KEYCODE_DPAD_DOWN 20
KEYCODE_DPAD_LEFT 21
KEYCODE_DPAD_RIGHT 22
KEYCODE_DPAD_CENTER 23
KEYCODE_VOLUME_UP 24
KEYCODE_VOLUME_DOWN 25
KEYCODE_POWER 26
KEYCODE_CAMERA 27
KEYCODE_CLEAR 28
KEYCODE_A 29
KEYCODE_B 30
KEYCODE_C 31
KEYCODE_D 32
KEYCODE_E 33
KEYCODE_F 34
KEYCODE_G 35
KEYCODE_H 36
KEYCODE_I 37
KEYCODE_J 38
KEYCODE_K 39
KEYCODE_L 40
KEYCODE_M 41
KEYCODE_N 42
KEYCODE_O 43
KEYCODE_P 44
KEYCODE_Q 45
KEYCODE_R 46
KEYCODE_S 47
KEYCODE_T 48
KEYCODE_U 49
KEYCODE_V 50
KEYCODE_W 51
KEYCODE_X 52
KEYCODE_Y 53
KEYCODE_Z 54
KEYCODE_COMMA 55
KEYCODE_PERIOD 56
KEYCODE_ALT_LEFT 57
KEYCODE_ALT_RIGHT 58
KEYCODE_SHIFT_LEFT 59
KEYCODE_SHIFT_RIGHT 60
KEYCODE_TAB 61
KEYCODE_SPACE 62
KEYCODE_SYM 63
KEYCODE_EXPLORER 64
KEYCODE_ENVELOPE 65
KEYCODE_ENTER 66
KEYCODE_DEL 67
KEYCODE_GRAVE 68
KEYCODE_MINUS 69
KEYCODE_EQUALS 70
KEYCODE_LEFT_BRACKET 71
KEYCODE_RIGHT_BRACKET 72
KEYCODE_BACKSLASH 73
KEYCODE_SEMICOLON 74
KEYCODE_APOSTROPHE 75
KEYCODE_SLASH 76
KEYCODE_AT 77
KEYCODE_NUM 78
KEYCODE_HEADSETHOOK 79
KEYCODE_FOCUS 80
KEYCODE_PLUS 81
KEYCODE_MENU 82
KEYCODE_NOTIFICATION 83
KEYCODE_SEARCH 84
TAG_LAST_KEYCODE
85 

 

android在adb下模拟长按事件

做过软件开发的人都知道,多数的软件开发后都会有压测,android系统也不例外,如果你正在做android系统克制化,甚至在克制化一些按键,那么你可能就会去压力测试这些按键是否健壮,你不可能让一个人一直重复的去按某个键或某几个键吧,因为压测一般都会持续1天到数天不等,你也可以写一个apk或者进程去压测,不过这样的扩展不够灵活,复用度不高,此时就会想到使用shell脚本去模拟这些按钮,如果想更换压测按钮只需更改其中的键值即可。

废话不多说,接下来我将讲解三种模拟长按的方式:

第一种:在adb下使用 input keyevent --longpress <键值>

比如长按home键 可以使用:input keyevent --longpress KEYCODE_HOME ,KEYCODE_HOME就是android为home键定义的键值,它是一个宏,其实是一个数字。

当然你也可以使用数字:input keyevent --longpress 3 键值3对应的宏便是KEYCODE_HOME,也能模拟长按home键。android中还有很多键值,一个数字键,字母键,我们不可能记住这么多数字,所以还是推荐使用第一种宏的方式。这些宏对应的键值网上与很多对应表我就不一一列举了,这个就比较全请参考:Android KEYCODE键值对应大全

那这种长按的方式有什么缺点呢:长按时间太短。比如我们要模拟长按电源键呼出关机菜单或者长按切换应用键呼出分屏(android7.0新功能),这种方式长按时间太短。只适用与拖动选择时一开始的长按情况。

第二种:在adb下使用input swipe <x1> <y1> <x2> <y2> [duration(ms)]

上面这条指令实际上是滑动的指令,x1,y1和x2,y2分别是两个坐标,duration是从x1,y1处滑动到x2,y2处规定的时间。为什么滑动可以模拟长按呢:只要我们两个坐标之间的差值足够小,还在当前这个按钮的范围内,android系统就会认为我们进行了长按某个按钮的操作,当然这只能模拟虚拟按钮,因为实体键我们是没法获取到它的坐标的。

那么什么情况才能满足坐标足够小呢,就我看来只需要 在原坐标值上加1即可:

input swipe <x1> <y1> <x1+1> <y1+1> [duration(ms)],由于1在屏幕中占的位置很小,肯定不会超过一般按钮的大小,因此只要定位准确按钮的坐标位置,这个方法就可以实现长按某个虚拟按钮。那么如何确定某个按钮的坐标位置成为关键。

android 提供了一个方法用于获取来自上层发送到驱动的input事件的方法——getevent,这个方法会去获取android input设备文件上的键值和坐标值。我们只需要在adb下运行这个命令,即可获取我们当前点击按钮的坐标值。建议你将这个功能运行在后台 只需要运行getevent & 这条指令,每次我们手机或者平板上的任意一点,都会打出对应的坐标值。如图便是我点击home键打印的坐标情况,当然如果你按了实体键,将会打印出键值,而不是坐标,接下来我会讲。

ADB 在APP自动化测试应用汇总
add device 1: /dev/input/event0: 代表 一个设备文件,用以标志一个输入设备,当然这样的输入设备文件可以有多个,分别对应不同的设备驱动,比如androidTV可能有遥控器,键盘等等。由于我这里使用的是模拟器,只有一个设备文件。

第一列:/dev/input/event0 就代表的不同device收到了一个事件

第二列:0001 代表一个type

第三列:如果是点击屏幕上的虚拟按键,这个值是014a用以标识点击了屏幕。如果是0代表x值,1代表y值,也是16进制。其他值代表键值。

第四列:00000001 代表value 一般 1代表按下,0代表放开。其它值则代表坐标(虚拟按键)

如此我们就可以看到,点击一次屏幕,就会打印出点击这个点的坐标值,我们就将该坐标值转化为10进制,在使用swipe命令就可以实现长按了,比如上图中的home键长按即可表示为:

input swipe 546 1860 547 1861 2000 就这么简单,赶紧去试一试吧。

这种方法虽然能够控制长按的时间,不过只能模拟虚拟按键的情况。如果想模拟实体键,比如android TV遥控器上就会有很多实体键。此时就要使用第三中方案。

第三种:sendevent device type code value

既然有getevent获取input事件,那么就肯定会有sendevent 发送事件,同样的道理,这个方法就会向设备文件发送特定的键值,从而驱动能将改键值上报给应用或者是系统。举一个简单例子:sendevent /dev/input/event0 1 213 1 该命令是向设备文件/dev/input/event0 发送了一个键值为213的按下(down)操作。sendevent /dev/input/event0 1 213 0 命令则是发送一条指令给设备文件,让213这个键松开(up)。这样一按一放,我们中间只要让其睡几秒即可实现长按操作。那么关键是如何确定这个按键的键值,这里要声明的是这个键值和我们方案一中提到的类似KEYCODE_HOME这样的宏定义个值不一样,之后我会将为什么,因此你会发现当你用方案一中 android键值映射表中键值来使用 sendevent的时候不起作用。那么如何找到这个键值是关键。

1、你可以使用第二个方案中提供的getevent方法获取这个键值,即你按一个实体键依然会打印实体键的键值。下图便是我按下power键后打印的键值:

ADB 在APP自动化测试应用汇总0074便是power键的键值,转化为10进制为116,因此你现在就可以大胆的实现,你长按power键的共能了,只需要使用如下脚本即可:

#!/bin/sh
sendevent /dev/input/event0 1 116 1
sendevent /dev/input/event0 0 0 0
echo "down"
sleep 3
sendevent /dev/input/event0 1 116 0
sendevent /dev/input/event0 0 0 0
echo "up"

此时即可模拟长按power键的效果:

ADB 在APP自动化测试应用汇总

那万一我们手机或者当时没有这个按键该怎么办呢,比如我要模拟一个游戏手柄上的按键,而此时我又没有游戏手柄,该怎么获取这些键值呢,这就涉及到第二种获取键值的方式。

2、在android系统中作为键值会有两次映射,第一次是将驱动的键值映射到系统,再由系统framework将其映射为我们使用的键值(即我们方案一中提到的那些宏KEYCODE_HOME),作为程序员,我们不希望我们每次使用的键值都不一样,因此android系统将底层抛出的键值再做一次映射确保framework和应用使用的键值保持一致,程序员写应用的时候再也不用担心不同厂家生产的手机或者电视使用的键值不同,因为android系统已经定义好标准了。比如home键键值就是3,无论你的应用在任何平台使用都不会出现这个3的键值变成其他的键。

然而不同的厂商会定义自己特殊的键,这些键又是在哪里去定义呢,android系统提供了一个映射文件,你可以使用 dumpsys input 去查找这个文件。如图:

ADB 在APP自动化测试应用汇总图中显示了两个.kl文件即是映射文件。分别是:

/system/usr/keylayout/qwerty.kl和/system/usr/keylayout/Generic.kl这两个文件,Generic.kl是默认文件,如果厂商没有其他的克制化.kl文件,系统就会默认使用这个文件,因此我们就需要在/system/usr/keylayout/qwerty.kl文件中去寻找我们的底层驱动使用的键值。如图:

ADB 在APP自动化测试应用汇总进入/system/usr/keylayout目录,你会看到很多.kl文件,那就是不同厂家克制化的键值对应关系,上图中就可以看到我的设备驱动中使用的键值对应关系了,我们可以看到POWER键对应到驱动的键值就是116,所以你理解了为什么使用getevent获取的键值是16进制的0066了吧,因为在驱动或者设备文件使用的是/system/usr/keylayout/qwerty.kl(不同厂家不一样,具体你可以使用dumpsys input查看)中的键值。这样既能够满足厂家的克制化需求,也能满足上层应用对键值的要求,是不是很合理呢。

此时如果你有兴趣当一个打破常规的人,你可以将CAMERA的键值也改成116,此时你就可以使用power键拍照了,你也可以把home键改成锁屏键,不仅如此你还可以自己添加自己想要的一些按键,自定义按键,只需要你的手机root后,连上adb,修改这个文件,重启手机即可,是不是很炫酷,赶紧试试吧。

 

Android单击、长按获取当前触点坐标下(TextView)文字字符


package com.*.*.*.utils;

import android.graphics.Rect;
import android.text.Layout;
import android.widget.TextView;

public class TextViewUtils
{
/**
获取TextView某一个字符的坐标位置
@return 返回的是相对坐标
@parms tv
@parms index 字符索引
*/
public static Rect getTextViewSelectionRect(TextView tv, int index) {
Layout layout = tv.getLayout();
Rect bound = new Rect();
int line = layout.getLineForOffset(index);
layout.getLineBounds(line, bound);
int yAxisBottom = bound.bottom;//字符底部y坐标
int yAxisTop = bound.top;//字符顶部y坐标
int xAxisLeft = (int) layout.getPrimaryHorizontal(index);//字符左边x坐标
int xAxisRight = (int) layout.getSecondaryHorizontal(index);//字符右边x坐标
//xAxisRight 位置获取后发现与字符左边x坐标相等,如知道原因请告之。暂时加上字符宽度应对。
if (xAxisLeft == xAxisRight)
{
String s = tv.getText().toString().substring(index, index + 1);//当前字符
xAxisRight = xAxisRight + (int) tv.getPaint().measureText(s);//加上字符宽度
}
int tvTop=tv.getScrollY();//tv绝对位置
return new Rect(xAxisLeft, yAxisTop+ tvTop, xAxisRight, yAxisBottom+tvTop );

}

/**获取TextView触点坐标下的字符
@param tv tv
@param x 触点x坐标
@param y 触点y坐标

@return 当前字符
*/
public static String getTextViewSelectionByTouch(TextView tv, int x, int y) {
String s = "";
for (int i = 0; i < tv.getText().length(); i++)
{
Rect rect = getTextViewSelectionRect(tv, i);
if (x < rect.right && x > rect.left && y < rect.bottom && y > rect.top)
{
s = tv.getText().toString().substring(i, i + 1);//当前字符
break;
}
}
return s;
}
}
在 点击事件中通过获取触点坐标后调用 TextViewUtils.getTextViewSelectionByTouch(tv, x, y) 即可获取当前字符。

android自动化测试中实现长按并拖动

Android获取Toast的String解析

上一篇:广播数据写入界面的心得体会


下一篇:依赖倒转原则