【问题标题】:Is it possible to use adb commands to click on a view by finding its ID?是否可以使用 adb 命令通过查找其 ID 来单击视图?
【发布时间】:2017-07-15 15:27:45
【问题描述】:

假设我有一个应用程序(在调试/发布版本中,无论是否由我制作),它具有特定视图的 ID。

可以调用adb命令点击这个视图吗?

我知道可以让它点击一个特定的坐标,但是可以使用 ID 代替吗?

我问这个是因为我知道“布局检查器”工具(可通过 Android Studio 获得)和“视图层次结构”工具(可通过“Android 设备监视器”获得,之前通过 DDMS 使用)可以显示视图(甚至它们的坐标和边界框),因此在执行一些自动测试时,它可能是模拟触摸的更好方法。

如果需要,我可以使用根方法。


编辑:我设置了一个赏金,以防有比我在自己的答案中写的更简单/更好的方法,即解析 "adb shell dumpsys activity top" 的结果。

我想知道是否可以获得屏幕上显示的视图坐标(当然还有大小),包括关于它们的尽可能多的信息(以识别每个视图)。 这也应该可以通过设备实现。也许某些输出数据与“监控”工具中可用的输出数据相同:

注意它如何获取视图的基本信息,包括文本、id 和每个视图的边界。

正如我所读到的,这可能通过 AccessibilityService 实现,但遗憾的是我无法理解它是如何工作的,它的功能是什么,如何触发它,它的要求是什么等等......

【问题讨论】:

  • 所以分析adb shell dumpsys activity top的输出,但这不是通用方法,因为该输出的格式将来可能会改变
  • 我不知道...但即使它可以从现在开始随时改变...
  • 安卓开发者:@AlexP。是的,使用uiautomator dump 命令(我不知道dump 子命令)
  • 来吧,你希望我为你写完整的项目吗?
  • 我已经告诉了你需要做的所有事情,但你似乎不想自己做任何事情:为了在清单中添加我的服务,你做了什么尝试?您面临的问题是什么?

标签: android adb android-view


【解决方案1】:

使用上面 cmets 中的 @pskink 解释,我是这样实现的:

首先,我运行了这个命令:

adb shell dumpsys activity top

然后,我用这段代码来解析它:

public class ViewCoordsGetter {
    public static Rect getViewBoundyingBox(String viewIdStr) {
        final List<String> viewHierarchyLog = //result of the command
        for (int i = 0; i < viewHierarchyLog.size(); ++i) {
            String line = viewHierarchyLog.get(i);
            if (line.contains(":id/" + viewIdStr + "}")) {
                Rect result = getBoundingBoxFromLine(line);
                if (i == 0)
                    return result;
                int currentLineStart = getStartOfViewDetailsInLine(line);
                for (int j = i - 1; j >= 0; --j) {
                    line = viewHierarchyLog.get(j);
                    if ("View Hierarchy:".equals(line.trim()))
                        break;
                    int newLineStart = getStartOfViewDetailsInLine(line);
                    if (newLineStart < currentLineStart) {
                        final Rect boundingBoxFromLine = getBoundingBoxFromLine(line);
                        result.left += boundingBoxFromLine.left;
                        result.right += boundingBoxFromLine.left;
                        result.top += boundingBoxFromLine.top;
                        result.bottom += boundingBoxFromLine.top;
                        currentLineStart = newLineStart;
                    }
                }
                return result;
            }
        }
        return null;
    }

    private static int getStartOfViewDetailsInLine(String s) {
        int i = 0;
        while (true)
            if (s.charAt(i++) != ' ')
                return --i;
    }

    private static Rect getBoundingBoxFromLine(String line) {
        int endIndex = line.indexOf(',', 0);
        int startIndex = endIndex - 1;
        while (!Character.isSpaceChar(line.charAt(startIndex - 1)))
            --startIndex;
        int left = Integer.parseInt(line.substring(startIndex, endIndex));
        startIndex = endIndex + 1;
        endIndex = line.indexOf('-', startIndex);
        endIndex = line.charAt(endIndex - 1) == ',' ? line.indexOf('-', endIndex + 1) : endIndex;
        int top = Integer.parseInt(line.substring(startIndex, endIndex));
        startIndex = endIndex + 1;
        endIndex = line.indexOf(',', startIndex);
        int right = Integer.parseInt(line.substring(startIndex, endIndex));
        startIndex = endIndex + 1;
        //noinspection StatementWithEmptyBody
        for (endIndex = startIndex + 1; Character.isDigit(line.charAt(endIndex)); ++endIndex)
            ;
        int bot = Integer.parseInt(line.substring(startIndex, endIndex));
        return new Rect(left, top, right, bot);
    }
}

【讨论】:

  • 赞成票是怎么回事?这不起作用。使用line.contains("...") 进行线路验证是非常糟糕的软件设计。
  • @AlexP。你能解释一下为什么吗?正如我所发现的,每一行的语法都很好地匹配了这个规则。就像任何解析机制一样,它依赖于每一行的编写方式。不管你用什么,它都依赖它。
  • 该行的 dotted 部分是布尔标志,. 代表 false 值。因此,您的代码仅适用于将最后 3 个标志设置为 false 的视图(以及它们的所有父视图),但情况并非总是如此
  • 令人难以置信的是,一个人怎么能花费超过 2 周的时间来重新发明轮子,而不是使用平台开发人员专门创建的工具来完全按照您的要求进行操作。跨度>
  • @AlexP。哪3个标志?当然,我的解析可能是错误的(因为我找不到关于这个输出的文档,所以我自己想出来了),但它仍然需要解析。你能建议把它改成什么吗?关于糟糕的尝试,我没有看到任何其他答案。唯一的其他答案写在我的问题的 cmets 中,即在应用程序中创建代码。这不是我要求的(尽管我也想知道它是如何工作的)。我想知道 sdk-tool 是如何工作的,这样我就可以使用 PC 或 root 设备来做同样的事情。现在我只有 ids 和坐标。我也想要文字
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多