模仿Android系统下的鼠标键盘等输入设备,网上有很多资料。但是很都同意他们,他们甚至没有测试就复制了他们。这次我会写一点经验作为介绍。
0.背景知识:
众所周知,Android是一个基于Linux的系统。 Linux层与硬件交互,Framework通过JNI等渠道获取底层信息。
消息的传输方式为:Linux -> Framework -> Application
由于这种架构的特性,我们很容易知道在哪里以及如何添加鼠标和键盘消息。
1. 如何添加鼠标和键盘消息:
我们知道消息传递的路径,所以我们知道在哪里可以添加我们需要的键盘和鼠标消息。
1.1:添加了 Linux 驱动程序级别:
你可以写一个Linux Driver,注册一个字符设备驱动,创建一个主设备号为13的虚拟字符设备。使用Ioctl()与应用程序通信。
在Linux2.4时代,Sam曾经在S3C2440A上写过这样一个Driver,个人命名为VInput。可以实现以上功能。
优点:很少。
缺点:
1.Programming 比较复杂。 Linux 内核从2.4 到2.6,再到3.0。内核改了很多,只是注册字符设备驱动的方法和创建Device的方法改了很多,不再支持devfs了。
2.需要目标平台对应的Kernel Source Code。
3. 需要 root 权限才能插入 ko 文件。
总结:这个方法不好用。除了写Drivers的朋友,估计没人会这么做。曾经我想将 VInput 从 Linux Kernel 2.4 时代移植到 Linux Kernel3.0。但是内核符号变化太大了。它未能实现。
1.2:Linux 用户级别添加:
在某个版本的Linux Kernel 2.6 中,增加了UInput。即输入用户级驱动程序。此驱动程序允许应用程序通过与 /dev/uinput 交互来创建新的 Linux 输入设备。该设备可以是键盘、鼠标、绝对位置设备等。现在Linux级别已经模拟了特定的设备。那么Framework就会认为这是一个真正的输入设备。然后我们模拟的消息会一路上传,传递到App层面。
具体方法:
优点:
程序简单易用,无需内核源代码。可以模拟几乎所有常见的输入设备。
缺点:
这个程序最好写成一个使用 NativeC 程序的可执行程序。只在Linux层运行。
但是如果你只是使用JNI,让它成为Android上层程序调用的库。您可能会遇到一个问题:权限不足。
在Android系统下,我们经常看到/dev/input设备的拥有者是system。同一组内其他用户的权限往往是不可读写的。但是一般的APK拥有者不是system,所以设备(/dev/uinput)是不能读写的。因此,该方法在JNI模式下可能会失败。
除非/dev/uinput的权限是666.,否则没有问题。
(当然有两种方法可以突破,不过那是另外一个话题了,可以看下面的文档系统签名部分:
)
总结:这个方法 Sam 一直在实践中使用。效果非常好。
1.3:框架级修改:
这个方法只是理论上可行,可以通过阅读Framework中/dev/eventX的JNI部分来启动。但实际上,没有人会破坏Framework这个功能的稳定性。所以这只是理论上可行。一位同事以前研究过这个。但最终没有做到。
总结:除非您有特殊需要,否则不要这样做。
1.4:使用 Instrumentation 发送键盘和鼠标消息:
Instrumentation 可以监控系统和应用程序之间的通信。您可以使用它向应用程序发送鼠标和键盘消息。有点像 Windows 下的 Hook。
具体方法:
如果您只想向此应用程序发送键盘和鼠标消息。
Instrumentation inst=new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_A);
inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 200, 0));
SystemClock.sleep(1000);
inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 200, 200, 0));
SystemClock.sleep(1000);
inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 200, 200, 0));
向当前聚焦的窗口发送键盘和鼠标消息。
可以使用:
sendKeyDownUpSync()
sendKeySync()
通过sendCharacterSync()等方式发送键盘消息。
您可以使用 sendPointerSync() 发送鼠标消息。
但是如果您想将键盘和鼠标消息发送到其他应用程序窗口。只是这样做会导致错误并且程序会崩溃。
java.lang.SecurityException:注入到另一个应用程序需要 INJECT_EVENT 权限。
好的,让我们添加这个权限。
在AndroidManifest.xml 的Permissions 菜单中,添加Uses Permission。选择 INJECT_EVENT。
此时增加了uses-permission android:name="android.permission.INJECT_EVENT"。
但是编译会报错,这个权限只对系统APP有效。
呵呵,那我们还要加系统权限。
android:sharedUserId="android.uid.system">
加入。
生成未签名的 APK。使用 apktools 添加系统签名文件。通过这种方式,您可以向其他应用发送鼠标和键盘消息。
优点:简单且易于实施。
缺点:如果将鼠标和键盘发送给其他程序,则需要系统签名文件。而且有些程序估计是从低层得到消息,所以这类程序不会有响应。
总结:我想向其他APP窗口发送消息。必须需要系统签名。
一般情况下,模拟Android系统中的鼠标和键盘。使用UInput方案,在Linux层制作NativeC可执行程序是最安全的。输入设备是直接在 Linux 级别创建的。
如果使用Instrumentation方式,一方面可能有些app吃不完,另一方面如果你想给其他app发消息。您需要一个系统签名文件。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/bofangqi/article-381986-1.html
择机升级应该是选项了
困兽之斗