如何在Android上可靠地模拟触摸事件而不需要root权限(类似于Automate和Tasker)?

19

如何在Android上可靠地模拟触摸事件(不需要Root权限),并使其在我的后台服务之外的Java应用程序中运行?

虽然此问题以前已经被问过,但是大多数答案都使用ADB (例如 如何在Android设备上模拟触摸事件?)。

https://github.com/chetbox/android-mouse-cursor使用无障碍功能提供了一个很好的解决方案,但是它并不是非常可靠,因为并不是所有视图都对其做出响应,并且大部分时间游戏根本没有反应。

private void click() {
  AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
  if (nodeInfo == null) return;

  AccessibilityNodeInfo nearestNodeToMouse = findSmallestNodeAtPoint(nodeInfo, cursorLayout.x, cursorLayout.y + 50);

  if (nearestNodeToMouse != null) {
    logNodeHierachy(nearestNodeToMouse, 0);
    nearestNodeToMouse.performAction(AccessibilityNodeInfo.ACTION_CLICK);
  }

  nodeInfo.recycle();
}

这是目前由https://github.com/chetbox/android-mouse-cursor使用的代码。

Android版本为8.0,原生安卓系统。

有没有更好、更可靠的方法来从Java模拟这些触摸事件?先感谢了!


1
可能有改进较基于可访问性的方法,因为我不熟悉那段代码的细节。然而,通常情况下,可访问性和 root 是您唯一的选择。 - CommonsWare
嗨@Theo,你是怎么解决这个问题的? - 7geeky
1
我建议查看AccessibilityService#dispatchGesture和相应的GestureDescription文档。它们应该实际执行原始手势,不会依赖于开发人员正确实现onClick。 - Jabronie Man
例如,Team View QuickSupport 今天请求 特殊访问权限,这意味着任何请求此权限的应用程序都将能够在未经root的设备上模拟触摸事件吗? - user9672569
@CommonsWare,关于我在上一条评论中展示的截图,当您点击“打开设置”后,下一个屏幕是这个 - user9672569
显示剩余6条评论
1个回答

30

建议使用辅助功能服务和 AccessibilityService#dispatchGesture 方法来模拟自Android Nougat(API 24)以来的触摸事件。

以下是我用于模拟单击事件的方法。

// (x, y) in screen coordinates
private static GestureDescription createClick(float x, float y) {
    // for a single tap a duration of 1 ms is enough
    final int DURATION = 1;

    Path clickPath = new Path();
    clickPath.moveTo(x, y);
    GestureDescription.StrokeDescription clickStroke =
            new GestureDescription.StrokeDescription(clickPath, 0, DURATION);
    GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
    clickBuilder.addStroke(clickStroke);
    return clickBuilder.build();
}

// callback invoked either when the gesture has been completed or cancelled
callback = new AccessibilityService.GestureResultCallback() {
    @Override
    public void onCompleted(GestureDescription gestureDescription) {
        super.onCompleted(gestureDescription);
        Log.d(TAG, "gesture completed");
    }

    @Override
    public void onCancelled(GestureDescription gestureDescription) {
        super.onCancelled(gestureDescription);
        Log.d(TAG, "gesture cancelled");
    }
};

// accessibilityService: contains a reference to an accessibility service
// callback: can be null if you don't care about gesture termination
boolean result = accessibilityService.dispatchGesture(createClick(x, y), callback, null);
Log.d(TAG, "Gesture dispatched? " + result);

为了执行其他手势,您可能会发现测试AccessibilityService#dispatchGesture实现的代码非常有用
编辑:我在我的博客中发布了一篇文章,介绍了Android辅助功能服务的基础知识。请点击此处查看

3
有没有办法在低于24的API级别上实现触摸功能?我注意到你的应用程序“eva_facial_mouse”可以在Android手机上使用低于24的API级别执行轻敲操作。 - Akash Karnatak
4
@AkashKarnatak,这在一定程度上是可能的。EVA使用AccessibilityNodeInfo#performAction方法执行点击操作。这意味着你首先需要找到你想要点击的正确节点。通常这需要从根节点开始搜索一棵可访问性节点树。但并非所有应用程序都提供此类树结构,游戏就是一个典型例子,在我的经验中它们是主要的问题源。这是我在EVA中实际实现的方式:https://github.com/cmauri/eva_facial_mouse/blob/a77b50e3104df3bb8ae3b11e23768b5171bd2462/eviacam/src/main/java/com/crea_si/eviacam/a11yservice/AccessibilityAction.java#L328 - Cesar Mauri
2
这对我有用,谢谢!需要注意的是,可访问性服务的 XML 需要具有 "android:canPerformGestures=true" 才能使其正常工作。 - Flyview
1
@fatbringer 如果服务器(接收坐标的设备中的应用程序)在可访问性服务器的上下文中运行,则可能起作用。 - Cesar Mauri
1
我本意说的是“可访问性服务”,我的错误@fatbringer。 - Cesar Mauri
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接