美文网首页
AccessibilityService 如何点击文本链接(ur

AccessibilityService 如何点击文本链接(ur

作者: 善笃有余劫 | 来源:发表于2018-09-04 23:09 被阅读787次

前言

最近研究无障碍服务AccessibilityService ,操作点击微信文章

AccessibilityService 本身的使用还是很简单的,但是我遇到了 大问题。

无法点击消息里面的链接

原因分析

通常我们获得界面元素AccessibilityNodeInfo之后,调用performAction()模拟单击事件。

AccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); 

问题出在:

单纯的单击TextView本身并不能触发链接的跳转,需要单击在View的内容之上才可以。所以需要模拟点击位置才行,而不是点击View。
但是AccessibilityService 只能获得View的信息,并且只能对View进行操作。我需要找到一种点击屏幕位置的方法。

思路

对于模拟点击屏幕位置,经过我搜寻大概有两种方案。

1.使用adb

Android自动化之adb模拟操作(可实现按键精灵和手机输入法)

虽然可以满足点击屏幕任意位置的需求,但是需要一台电脑辅助。显然不适用我这种一个手机的需求。

2.使用测试框架

Android的Ui测试框架同样可以点击屏幕位置。当然UI测试框架有好几种,比如谷歌提供的 UiAutomator,Espresso等等。都可以点击和控制手机。

但是这样只能当成测试用例跑,并不能直接做成App。当然可以使用暴力的方法,比如使用命令行强行调用测试用例的方法。但这样无法满足设计效果,而且需要装3个App。不可取

解决

在我绞尽脑汁搜索,终于找到一篇使用AccessibilityService 可以点击任何位置的文章

Android7.0 AccessibilityService新增gesturedescription使用详解

没错就是使用AccessibilityService的dispatchGesture方法执行一个手势操作。

首先这个方法是7.0之后加入的所有最小版本改为24

执行的手势类为GestureDescription,实例化·GestureDescription`需要一段path路径。

学过自定义View的我们对path太熟悉不过了,所以我们可以使用dispatchGesture方法在屏幕上划出一个path,当然若path只是一个点的话,那就是单击事件。

所以整体的思路如下:

1.拿到节点元素
2.获得元素位置信息getBoundsInScreen
3.点击元素中心(默认)

根据ID获得节点

 public static AccessibilityNodeInfo getElementById(AccessibilityEvent event, String id, String packagename, int index) {
        if (event.getPackageName().equals(packagename) && event.getSource() != null) {
            List<AccessibilityNodeInfo> list = event.getSource().findAccessibilityNodeInfosByViewId(id);
            if (null != list) {
                for (AccessibilityNodeInfo info : list) {
                    if (info != null && list.indexOf(info) == index) {
                        return info;
                    }
                }
            }
        }
        return null;
    }

使用GestureDescription点击AccessibilityNodeInfo

public static void useGestureClick(AccessibilityNodeInfo info, AccessibilityService accessibilityService) {

        if (info == null) {
            return;
        }

        Rect rect = new Rect();
        info.getBoundsInScreen(rect);
        GestureDescription.Builder builder = new GestureDescription.Builder();
        Path path = new Path();
        path.moveTo(rect.centerX(), rect.centerY());
        GestureDescription gestureDescription = builder
                .addStroke(new GestureDescription.StrokeDescription(path, 100, 50))
                .build();
        accessibilityService.dispatchGesture(gestureDescription, new AccessibilityService.GestureResultCallback() {
            @Override
            public void onCompleted(GestureDescription gestureDescription) {
                super.onCompleted(gestureDescription);
            }
        }, null);
    }

两个方法合在一起使用如下,需要点击任意id元素,直接调用idGesturePlay即可。

 public static boolean idGesturePlay(AccessibilityEvent event, AccessibilityService accessibilityService, String id, String packagename, int index) {
        AccessibilityNodeInfo info = getElementById(event, id, packagename, index);
        if (info != null) {
            useGestureClick(info, accessibilityService);
            return true;
        }
        return false;
    }

同样这个点击方法可以解决某控件clickable为false的情况,因为这个点击事件和控件无关。

最后也是最重要的,配置xml配置手势支持

加入配置

android:canPerformGestures="true"

总结

本次问题的解决花了一天的功夫,几乎放弃。主要是市面关于AccessibilityService 的文章都很老,没有介绍到这个手势方法。这提醒我们,要密切注意版本的变化。一定的文档和搭梯子能力是必须的。

相关文章

网友评论

      本文标题:AccessibilityService 如何点击文本链接(ur

      本文链接:https://www.haomeiwen.com/subject/agygwftx.html