【问题标题】:How to simulate touch from background service with sendevent or other way?如何使用 sendevent 或其他方式模拟来自后台服务的触摸?
【发布时间】:2013-02-02 09:43:33
【问题描述】:

是否可以从后台应用程序(或服务)模拟触摸或运行 sh 脚本(模拟触摸)?

在没有 USB 或其他连接到 PC 的情况下测试 android 系统需要它,这就是为什么我不能(或不知道如何)使用 Monkey 或其他自动测试工具。

添加信息: 我找到了使用 root 运行 shell 命令的方法(经过测试的设备 root):

Unable to execute sendevent shell command through the android code(创建触摸模拟)。 Writing file on system partition(以root权限运行命令)

我也得到了模拟触摸的事件。

结果我有:

//sendevent commands to simulate touch (verify it work from cmd)
String[] touchEvent = { "sendevent /dev/input/event0 0 0 0\n",
                        "sendevent /dev/input/event6 3 53 499\n",
                        "sendevent /dev/input/event6 3 54 680\n",
                        "sendevent /dev/input/event6 3 58 40\n",
                        "sendevent /dev/input/event6 3 48 3\n",
                        "sendevent /dev/input/event6 3 57 0\n",
                        "sendevent /dev/input/event6 0 2 0\n",
                        "sendevent /dev/input/event6 0 0 0\n",
                        "sendevent /dev/input/event6 0 2 0\n",
                        "sendevent /dev/input/event6 0 0 0\n",
                        "sendevent /dev/input/event0 3 0 2\n",
                        "sendevent /dev/input/event0 0 0 0\n"};

try{
    Thread.sleep(2000);
    Process root = Runtime.getRuntime().exec("su");
    DataOutputStream os = new DataOutputStream(root.getOutputStream());             
    for(int i = 0; i < touchEvent.length; i++){
            Log.i(TAG, touchEvent[i]);  
            os.writeBytes(touchEvent[i]);
            os.flush();
    }
    root.waitFor();
} catch (IOException e) {
    Log.e(TAG, "Runtime problems\n");
    e.printStackTrace();
} catch (SecurityException se){
    se.printStackTrace();
} catch (InterruptedException e) {
    e.printStackTrace();
}

我没有任何例外,但它不是触摸模拟。

谁能帮忙解决这个问题?

如果有其他方法可以在 C 上使用 android ndk 或守护进程,请告诉我。

谢谢。

【问题讨论】:

  • 如果你在同一个本地网络上可以使用monkey,adb也可以通过无线工作。
  • 感谢您的回复。我知道,但应该没有任何连接(WiFi 和 BT 应该关闭)。
  • 嗨,你最终是如何做到这一点的?我遵循了您的所有步骤,但没有好消息,请查看我发布的问题 here

标签: android shell android-ndk android-service


【解决方案1】:

我无法执行“sendevent”命令,但为自己找到了另一种方法,希望对某人有所帮助。

对于模拟触摸,我使用了来自 android.app.Instrumentation 的 sendPointerSync(),它仅适用于“android.permission.INJECT_EVENTS”权限。要使用它,您应该将您的应用程序编译为系统应用程序。 为此,您应该按照以下步骤操作:

  1. 从安卓源获取文件:

    root-of-android-source-tree/out/host//framework/signapk.jar

    root-of-android-source-tree/build/target/product/security/platform.x509.pem

    root-of-android-source-tree/build/target/product/security/platform.pk8

  2. 使用获取文件为您的应用签名:

    命令“java -jar signapk.jar platform.x509.pem platform.pk8 YourApp-unsigned.apk”YourApp-signed.apk。

  3. adb install YourApp-signed.apk
    • 运行您的应用
    • 使用“adb shell ps”确认您的应用程序作为系统运行。

触摸模拟代码(模拟需要新线程):

Thread thread = new Thread(){
       @Override
       public void run(){
               Instrumentation m_Instrumentation = new Instrumentation();

               m_Instrumentation.sendPointerSync(MotionEvent.obtain(
                       SystemClock.uptimeMillis(),
                       SystemClock.uptimeMillis(),
                       MotionEvent.ACTION_DOWN,posx, posy, 0));
               m_Instrumentation.sendPointerSync(MotionEvent.obtain(
                       SystemClock.uptimeMillis(),
                       SystemClock.uptimeMillis(),
                       MotionEvent.ACTION_UP,width*4/5,height, 0));
       }
   };

清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp"
    **android:sharedUserId="android.uid.system"**
    android:versionCode="1"
    android:versionName="1.0" >

使用资源:

【讨论】:

  • 太好了,谢谢。你能告诉我你测试代码的Android版本是什么吗? Instrumentation 在 Lollipop 之前的版本上运行良好。我认为 Lollipop 需要一些额外的工作才能让仪器运行,你遇到过这个问题吗?或者,您知道任何可能的解决方案吗?
  • 我是2013年3月开发的,没有棒棒糖版本,或者只是预览版,我不记得了。所以我只在 Jelly Bean 上进行了测试。
  • v1kI 这是我第一次尝试获取系统文件。我不知道如何获取文件以使应用程序成为系统应用程序。你能帮我么?你能告诉我这样做的步骤吗?
  • 首先,您应该可以访问android OS 源代码,如果您尝试开发系统应用程序,您显然已经拥有系统,其中包含您的应用程序。有一个带有源的根文件夹,用于编译android,所以在我的回答中它等于“root-of-android-source-tree”。
  • v1k 谢谢我已经阅读了你的回答。我的问题是如何访问“root-of-android-source-tree”。是设备、电脑上的东西,还是我通过安装另一个组件得到的东西?如何访问根文件夹?
【解决方案2】:

当我发现一个更简单的解决方案时,我正要实施您的解决方案 - 希望它对某人有所帮助。由于您已经拥有 root 设备,因此您无需作为系统应用程序进行签名。

要模拟位置 (100,200) 的触摸,您只需使用 Runtime.exec 从服务中调用 input,如下所示:

Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
String cmd = "/system/bin/input tap 100 200\n";
os.writeBytes(cmd);
os.writeBytes("exit\n");
os.flush();
os.close();
process.waitFor();

【讨论】:

  • 这是一个更清洁的解决方案。不幸的是,它没有我非常需要的 touch_down、touch_up 或 move_to 等事件。 :(
  • 谢谢,它在我的galaxy s4 5.0.1 默认ROM 上工作,但它很少在一些设备上工作,如galaxy s6 6.0.1 rooted.It 太累了!为什么?
  • 看起来你甚至不需要设备root。一个普通的Runtime.getRuntime().exec("/system/bin/input tap 100 400"); 在标准的无根 Android 7.0 设备上为我做了诀窍。
  • 但是在没有“su”的情况下调用它只会在调用过程中起作用......(作为非提升的特权)。即水龙头不会被发送到其他进程。
  • 这个解决方案效果很好,但有一个警告:它相当慢。在我的手机上,从发送命令到注册触摸之间大约有 1 秒以上的延迟。
【解决方案3】:

您可以使用“滑动”输入。查看Input.java source code,您可以看到进行滑动所需的参数。

这是一个gist I made for simulating a swipe,用于通过点击而不是滑动来播放smove game,只是为了测试这一点。不过,您需要超级用户访问权限才能使用此实现。

【讨论】:

  • 您能否进行编辑以包含示例代码 sn-p 演示此解决方案?这即将成为“仅链接”的答案。
  • 源代码实际上非常明显且不言自明。刷卡:com.android.commands.input.Input.main(new String[] {"touchscreen", "swipe", "&lt;x1&gt;", "&lt;y1&gt;", "&lt;x2&gt;", "&lt;y2&gt;"[, "&lt;duration&gt;"]})(“触摸屏”在某种意义上是可选的,但更好地呈现。我想问的是代码真的有效吗?我是否需要在 AndroidManifest.xml 中声明权限或需要 root 访问权限?
  • ^ 参考上图:使用"blah blah".split(" ")更好的视觉表达
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-02
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多