现在的位置: 首页 > 移动开发 > 正文

Android 跨进程事件处理(一)——模拟点击、全局截屏

2017年09月12日 移动开发 ⁄ 共 4201字 ⁄ 字号 评论关闭

一直都是在这上面找资料,无耻的我真的不好意思不再分享了。

之前分配到的任务找资料一直也是找不到,运气好的遇到个提边角料的。但是都没有实质可以用的。发文档的也都是东贴贴别人的,西找找别人的。基本都是漫天胡扯。

好了,废话不多说。直接进入今天的主题吧。

 

模拟点击

模拟点击和截屏其实在应用本身中实现其实很简单。但是跨进程就相对比较麻烦了。比如,你写一个程序,自动启动微信,点微信界面里的某几个按钮。

如果你也是在找技术文档,那么你看到的什么input方法啦,模拟eventMotion方法之类的就不要去测试了,都不能跨进程。

正解是:getevent/sendevent(都需要应用于root的手机)

其实说白了,android里的各种事件,都是由/dev/input/event*管着的。管屏幕点击的event,一般是eventname中含有touch或者screen之类的event

例如我的手机(手机连在电脑上,进入命令行,获得adb的操作。命令是adb shell。如果发现不起作用,就把adb的环境变量配置一下,就是你的ndk根目录,配到path中就可以了。),例如我的手机,“#”代表我的手机是完全root的手机。

之后getevent -p你就会发现列出了很多设备。其中name中含有touch或者screen的应该就是管理手机触摸事件的event,不同的手机管理触摸事件的event可能不太相同。例如我的手机是event3。。其中给你还可以看到一些它给出的操作用例。

 

下面就来说这个怎么用吧。首先,你要给你所需要的那个event授予权限。授权的时候再cmd里你只需要用chmod 777 /dev/input/event3就可以了。但是在android程序代码里就不能这样了,你修改权限的时候是需要先获得root权限的。

具体用法:

调用下面的方法就可以了。RootCmd("chmod 777 /dev/input/event3");

	 public static boolean RootCmd(String cmd){
	        Process process = null;
	        DataOutputStream os = null;
	        try{
	            process = Runtime.getRuntime().exec("su") ;
	            os = new DataOutputStream(process.getOutputStream());
	            os.writeBytes(cmd+ "\n");
	            os.writeBytes("exit\n");
	            os.flush();
	            process.waitFor();
	        } catch (Exception e) {
	            return false;
	        } finally {
	            try {
	                if (os != null)   {
	                    os.close();
	                }
	                process.destroy();
	            } catch (Exception e) {
	            }
	        }
	        return true;
	    }

授权完毕后就可以模拟点击了。

该方法是我通过分析getevent的事件得到的(之后会给出getevent的模拟过程)

	private static String deviceTouchEvent = "event1";
	private static final String TAG="Ctrl_System_Action";
	// private static boolean isTouch

	public static void setMouseClick(int x, int y) {
		try {
			Log.i("", "ActivityManager test User click");
			/**
			 * sendevent /dev/input/event3 3 57 0 
			 * sendevent /dev/input/event3 3 48 1 
			 * sendevent /dev/input/event3 3 53 379 
			 * sendevent/dev/input/event3 3 54 483 
			 * sendevent /dev/input/event3 0 2 0
			 * sendevent /dev/input/event3 0 0 0 
			 * sendevent /dev/input/event3 3 48 0 
			 * sendevent /dev/input/event3 0 2 0 
			 * sendevent /dev/input/event3 0 0 0
			 */
			Log.i("", "ActivityManager test User temp click x="+x+",y="+y);
			// 获取可touch设备名称
			String eventFirst = "/dev/input/";
			String temp = "";
			// 默认触摸event为event1
			String myUserEventName = "event1";
			String tempEventName = "";
			// 获取root权限
			if (!isRoot) {
				RootCmd("chmod 777 /dev/input/event3");
				isRoot = true;
			}
			if(!isGetEventName){
				// 获取所有设备信息
				InputStream is = Runtime.getRuntime().exec("getevent -p")
						.getInputStream();
				InputStreamReader isReader = new InputStreamReader(is);
				BufferedReader bufferReader = new BufferedReader(isReader);
				// 鉴别设备
				while ((temp = bufferReader.readLine()) != null) {
					Log.i("", "ActivityManager test User getEventString temp = "
							+ temp);
					// 先将 event*存下来
					if (temp.indexOf(eventFirst) >= 0) {
						if ((temp.indexOf(eventFirst) + eventFirst.length()) < temp
								.length()) {
							tempEventName = temp.substring(temp.indexOf(eventFirst)
									+ eventFirst.length());
						}
						Log.i("","ActivityManager test User getEventString EventName = "
										+ tempEventName);
					}
					// 判断设备是否为屏幕设备,如果是就将event保存下来
					if (temp.indexOf("name:") >= 0
							&& (temp.indexOf("touch") >= 0 || temp
									.indexOf("screen") >= 0)) {
						myUserEventName = tempEventName;
						deviceTouchEvent = myUserEventName;
						Log.i("",
								"ActivityManager test User getEventString TrueEventName = "
										+ tempEventName);
						break;
					}
				}
				isGetEventName = true;
			}
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 3 57 0");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 3 48 1");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 3 53 "+x);
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 3 54 "+y);
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 0 2 0");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 0 0 0");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 3 48 0");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 0 2 0");
			Runtime.getRuntime().exec("sendevent /dev/input/"+deviceTouchEvent+" 0 0 0");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.i("", "ActivityManager test User click e=" + e.toString());
			e.printStackTrace();
		}
	}

 

上述代码中找出event的方法可以忽略,主要在Runtim.getRunTim().exec那儿。完成一次点击,需要将上述的9条adb shell命令全部执行一次。这些命令你也可以再cmd里手动输入测试。只不过手动比较慢,点击可能会变成长按。

下面就给大家讲getevent的具体用法:

在cmd里输入命令getevent,这个时候你再去点击屏幕的时候,就会把你点击的点给记录下来。

如图,我点击的是x=1b3,y=2aa的点。

看出来了吧,系统记录的是16进制的。你只需要转换一下就可以了。以第一条为例,转换完的数据是 3 57 0;

 

截屏;

截屏相信能够支持的也是很多,这里就介绍一个个人感觉比较好的吧。

该方法只适用于4.0以后的版本,4.0以前的版本跨进程截屏是需要JNI方法的。

直接调用我上面的RootCmd方法,输入截屏命令就可以了。

RootCmd("screencap -p "+filePath);

同模拟点击不同,模拟点击只需要获取一次root权限即可,而截屏,每次调用是都需要root的。所以直接掉封装好的RootCmd方法就可以了。

4.3貌似还有screenshot方法。这个没怎么试过。2.3的手机就别想这个方法了,截不出来的,倒是会生成一个文件,但是是一个有大小没图像的东东。目前没找到原因。

 

 

 

 

 

 

 

 

 

抱歉!评论已关闭.