对于安卓系统来说,模拟用户操作是一件很危险的事情,因此到目前我所使用过的系统(Android 7以下)均没有开放模拟触控权限。本文总结了目前已知可行的跨进程触控操作方法,基本都需要Root权限或系统签名。
一、Instrumentation框架
| 项目 | 描述 |
| ——-|: ——:|
| 权限要求 | 同进程下无要求 |
| 权限要求 | 跨进程下需要系统签名 |
| 可用操作 | 点击、滑动、拖拽、多点触控、按键操作 |
| 上手难度 | 简单 |
Instrumentation框架主要是用来控制和测试应用程序的,一般用在写单元测试的时候,可模拟用户所有操作。
代码如下:
Instrumentation inst = new Instrumentation();
inst.sendPointerSync(event);//发送鼠标操作
inst.sendKeyDownUpSync(keyCode);//发送按键操作```
例子:模拟鼠标滑动
//模拟按下
MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, positionX, positionY, 0);
//模拟移动
MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, positionX, positionY, 0);
//模拟抬起
MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, positionX, positionY, 0);
> 常见触摸操作
> public static final int ACTION_DOWN = 0; 单点触摸动作
> public static final int ACTION_UP = 1; 单点触摸离开动作
> public static final int ACTION_MOVE = 2;触摸点移动动作
> public static final int ACTION_CANCEL = 3;触摸动作取消
> public static final int ACTION_OUTSIDE = 4;触摸动作超出边界
> public static final int ACTION_POINTER_DOWN = 5;多点触摸动作
> public static final int ACTION_POINTER_UP = 6;多点离开动作
PS:在同进程下,可以使用 *view.onTouchEvent(motionEvent);* 来对控件输入模拟操作
###系统权限获取方法
在AndroidManifest.xml文件中增加系统权限 android:sharedUserId="android.uid.system",并对生成的apk包,进行系统签名
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/6338331-fbc3100a6193c30f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
系统签名有两种方法
####方法一:使用签名文件签名方法
Android的签名文件存放于系统源码的 build/target/product/security/目录下
![](http://upload-images.jianshu.io/upload_images/6338331-378f87f773ef75ab?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 该目录下有 media.pk8、media.x509.pem、platform.pk8、platform.x509.pem、shared.pk8、shared.x509.pem、testkey.pk8、testkey.x509.pem等签名文件,不同的签名文件,对应不同的权限。Android默认的签名文件为testkey.pk8、testkey.x509.pem。
将对应权限的签名文件platform.pk8、platform.x509.pem, 签名工具 signapk.jar, 以及需要签名的apk(假设 old.apk) 放到同一目录下,打开linux终端(windows cmd也可以),进入该目录,进行重新签名:
java -jar signapk.jar platform.x509.pem platform.pk8 old.apk new.apk
得到的new.apk就是带系统签名的安装包了。
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/6338331-81ea153d2266673b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####方法二:在系统源码环境下用make来编译(需Linux环境)
** 1.修改Android.mk文件**
Android.mk文件时在Linux下用交叉编译连编译的时候才用到的,eclipse中不会自动生成。我们在Android.mk文件中添加LOCAL_CERTIFICATE := platform这一行。例如:
>LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Settings
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
** 2.把项目放到源码下,用mm命令编译**
***
#二、ADB命令 input
| 项目 | 描述 |
| -------|: ------:|
| 权限要求 | 需要Root权限|
| 可用操作 | 点击、直线滑动、拖拽、按键操作、英文输入 |
| 上手难度 | 简单 |
*用adb的input命令来模拟简单的输入,用法比较受限*
>usage: input ...
input text //输入文字(中文不支持)
input keyevent //keyevent按键
input [touchscreen|touchpad|touchnavigation] tap <x> <y>//点击屏幕
input [touchscreen|touchpad|touchnavigation] swipe <x1> <y1> <x2> <y2> //屏幕滑动
input rotationevent 0 1->90 2->180 3->270> //顺时针旋转
代码如下:
//su命令函数
public class UtilShell{
private static DataOutputStream os = null;
public static final boolean exe(String cmd){
try {
if (os == null) {
Process process = Runtime.getRuntime().exec(“su”);
os = new DataOutputStream(process.getOutputStream());
}
os.writeBytes(cmd + “\n”);
os.flush();
return true;
}catch (IOException ex) {
Log.w(“ROOT”, “Can’t get root access”, ex);
} catch (SecurityException ex) {
Log.w(“ROOT”, “Can’t get root access”, ex);
} catch (Exception ex) {
Log.w(“ROOT”, “Error executing internal operation”, ex);
}
return false;
}
}
//模拟点击坐标(222,333)代码
UtilShell.exe(“input touchscreen tap “+222+” “+333);
>附按键表 KeyCode Keyevent Value 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 *** #三、Shell命令 sendevent | 项目 | 描述 | | -------|: ------:| | 权限要求 | 需要Root权限| | 可用操作 | 点击、滑动、拖拽 | | 上手难度 | 较难 | *getevent&sendevent 是Android系统下的一个工具,可以模拟多种按键和触屏操作,产生的是raw event,raw event经过event hub处理产生最终的gesture事件,sendevent用于发送input事件,源码位于Android SDK的system/core/toolbox下(sendevent.c getevent.c)。* ###用法 ####1. 使用所有getevent命令,输出所有event设备的基本信息 **注意:这里的数字都是16进制。** >Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device] -t: show time stamps -n: don't print newlines -s: print switch states for given bits -S: print all switch states -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64) -d: show HID descriptor, if available -p: show possible events (errs, dev, name, pos. events) -i: show all device info and possible events -l: label event types and names in plain text //将type、code、value以对应的常量名称显示 -q: quiet (clear verbosity mask) -c: print given number of events then exit //输出x条信息后退出 -r: print rate events are received ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/6338331-9735a4341d0cb192.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ####2. 使用sendevent命令模拟操作 **注意:这里的数字都是10进制。** >命令用法 sendevent [device] [type]
[value]
*具体定义可从kernel/include/linux/input.h中获得
提供个链接 http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/input.h*>情况1:在某坐标点上点击一次(x坐标为40,y坐标为210)
adb shell sendevent /dev/input/event0 3 0 40 //鼠标移到x坐标40
adb shell sendevent /dev/input/event0 3 1 210 //鼠标移到y坐标210
adb shell sendevent /dev/input/event0 1 330 1 //鼠标按下
adb shell sendevent /dev/input/event0 0 0 0 //同步(不可缺少)
adb shell sendevent /dev/input/event0 1 330 0 //鼠标抬起
adb shell sendevent /dev/input/event0 0 0 0 //同步(不可缺少)>情况2:模拟滑动轨迹(开始于[100,200],止于[108,300])
adb shell sendevent /dev/input/event0 3 0 100 //鼠标移到x坐标100
adb shell sendevent /dev/input/event0 3 1 200 //鼠标移到y坐标200
adb shell sendevent /dev/input/event0 1 330 1 //鼠标按下
adb shell sendevent /dev/input/event0 0 0 0 //同步
adb shell sendevent /dev/input/event0 3 0 101 //鼠标移到x坐标101
adb shell sendevent /dev/input/event0 0 0 0 //同步
…………………… //需一点一点移动,这里省略
adb shell sendevent /dev/input/event0 3 0 108 //鼠标移到x坐标108
adb shell sendevent /dev/input/event0 0 0 0 //同步
adb shell sendevent /dev/input/event0 1 330 0 //鼠标抬起
adb shell sendevent /dev/input/event0 0 0 0 //同步代码如下:
//模拟操作与input命令相似
UtilShell.exe("sendevent /dev/input/event0 0 0 0");*此方法基本能满足模拟操作的所有要求,据说有一款叫aPaint的软件对此方法开发有极大帮助* *** #四、新增虚拟USB鼠标设备 | 项目 | 描述 | | -------|: ------:| | 权限要求 | 需要修改系统文件| | 可用操作 | 所有鼠标操作 | | 上手难度 | 极难 | 暂无思路,仅供参考!