11

【android】技术调研:用代码模拟屏幕点击、触摸事件 | iTimeTraveler

 3 years ago
source link: https://itimetraveler.github.io/2016/06/02/%E3%80%90Android%E3%80%91%E6%8A%80%E6%9C%AF%E8%B0%83%E7%A0%94%EF%BC%9A%E7%94%A8%E4%BB%A3%E7%A0%81%E6%A8%A1%E6%8B%9F%E5%B1%8F%E5%B9%95%E7%82%B9%E5%87%BB%E3%80%81%E8%A7%A6%E6%91%B8%E4%BA%8B%E4%BB%B6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在Android中,有些场景需要使用代码来模拟人的操作,比如微信自动抢红包、UI测试等都需要模拟实现点击事件(Click)、触摸事件(Touch)、键盘事件(KeyBoard)等。那么,有没有现成的方案可以实现呢?答案当然是肯定的啦,往下看。

经过调研发现,给系统模拟注入输入事件有如下几种方式:

一、使用shell命令

使用android自带的adb shell,里面自带一个input工具,使用方法如下:

adb shell #进入系统
input keyevent KEYCODE_BACK #模拟按返回键
input keyevent KEYCODE_HOME #模拟按Home键

还可以直接输入点击屏幕的事件,模拟点击屏幕:

input tap 100 200  #在屏幕坐标(100, 200)处点击

详细的用法如下:

二、使用 Instrumentation

Instrumentation本身是Android用来做测试的工具,可以通过它监测系统与应用程序之间的交互。详情可以参考官方文档[Test Your App]。我们这里只关注怎么使用Instrumentation产生发送按键或者触屏事件。

它可以发送按键:

Instrumentation mInst = new Instrumentation();  
mInst.sendKeyDownUpSync(KeyEvent.KEYCODE_CAMERA);

也可以发送触屏事件:

Instrumentation mInst = new Instrumentation();  
mInst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0); //x,y 即是事件的坐标
mInst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0);

与Shell工具一样,还有类似sendStringSync()发送文本,sendTrackballEventSync()发送轨迹球事件等方法。

sendCharacterSync(int keyCode)            //用于发送指定KeyCode的按键
sendKeyDownUpSync(int key) //用于发送指定KeyCode的按键
sendPointerSync(MotionEvent event) //用于模拟Touch
sendStringSync(String text) //用于发送字符串

需要注意的是,这些方法均不可以在UI主线程中执行,必须放到子线程中调用,否则就会报错。另外,使用上面的方法,需要在AndroidManifast.xml中申明如下权限:

<uses-permission android:name="android.permission.INJECT_EVENTS"/>

三、使用Android内部API

在Android系统中,有些内部的API提供注入事件的方法。因为是内部API,在不同版本上可能变化比较大。使用如果想在普通App中使用,可能需要通过反射机制来调用。

在Android API 16之前,WindownManager有相应的方法提供注入事件的方法,如下:

IBinder wmbinder = ServiceManager.getService("window");  
IWindowManager wm = IWindowManager.Stub.asInterface(wmbinder); //pointer
wm.injectPointerEvent(myMotionEvent, false); //key
wm.injectKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A), false);
wm.injectKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A), false); //trackball
wm.injectTrackballEvent(myMotionEvent, false);

在API 15之后,引入了InputManager,把上面的哪些injectXXXEvent()方法从WindowManager中移除了。使用方法类似:

IBinder imBinder = ServiceManager.getService("input");  
IInputManager im = IInputManager.Stub.asInterface(imBinder);

//inject key event
final KeyEvent keyEvent = new KeyEvent(downTime, eventTime, action,
code, repeatCount, metaState, deviceId, scancode,
flags | KeyEvent.FLAG_FROM_SYSTEM |KeyEvent.FLAG_KEEP_TOUCH_MODE | KeyEvent.FLAG_SOFT_KEYBOARD,
source);
event.setSource(InputDevice.SOURCE_ANY)
im.injectInputEvent(keyEvent, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);

//inject pointer event
motionEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
im.injectInputEvent(motionEvent, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);

从API 16开始,InputManager就成了一个公开的类了,可以通过如下方法获得InputManager实例:

InputManager im = (InputManager) getSystemService(Context.INPUT_SERVICE);

注意,使用injectEvent()同样需要申明android:name=”android.permission.INJECT_EVENTS”权限。

四、可以考虑使用Monkey测试框架

这种方案就是希望能够模拟Android Monkey的测试方法,不过博主并没有来得及对这方面进行深入的研究,可以参考这篇文章Android Monkey源码解析

【参考资料】:

1、Android模拟产生事件
2、Android 模拟键盘鼠标事件(Socket+Instrumentation实现)
3、Android Monkey源码解析


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK