关于AccessibilityService点击无效解决方案

5,630 阅读1分钟

1.为什么会点击失效?

        例如微信的通讯录页面使用uiautomator捕获的界面属性,可以看到 clickable="false", 当前页面的ListView中item都是没有点击事件的. clickable=false的控件使用AccessibilityService点击都是无效的.

2.解决方案:

(1)配合ADB命令进行屏幕位置模拟点击(缺点是需要设备ROOT)

(2)使用AccessibilityService API7.0 中的dispatchGesture()的方法(只兼容Android7.0以上设备)


输出adb命令:

public void adbShell(String cmd) {
    try {
        // 申请获取root权限,这一步很重要,不然会没有作用
        Process process = Runtime.getRuntime().exec("su");
        // 获取输出流
        OutputStream outputStream = process.getOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(
                outputStream);
        dataOutputStream.writeBytes(cmd);
        dataOutputStream.flush();
        dataOutputStream.close();
        outputStream.close();
        Log.d(TAG, "adbShell: 输出命令:" + cmd + "成功");
    } catch (Throwable t) {
        t.printStackTrace();
        Log.d(TAG, "adbShell: 输出命令:" + cmd + "失败");
    }
}

AccessibilityService 根据id和text获取控件节点的坐标位置后调用adb坐标点击命令

public void adbClick(final String id, final String tv, int delay) {
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            AccessibilityNodeInfo root = service.getRootInActiveWindow();
            if (root == null) {
                Log.d(TAG, "无Root:" + id);
            }
            List<AccessibilityNodeInfo> tab = root.findAccessibilityNodeInfosByViewId(id);
            if (tab == null || tab.size() == 0) {
                Log.d(TAG, "找不到点击控件:" + id);
                return;
            }
            for (AccessibilityNodeInfo info : tab) {
                if (info.getText() != null && tv.equals(info.getText().toString())) {
                    Rect rect = new Rect();
                    info.getBoundsInScreen(rect);
                    Log.d(TAG, "adb点击位置: " + rect.top + "," + rect.bottom + "," + rect.left + "," + rect.right);
                    adbShell("input tap " + rect.left + " " + rect.top);
                } else Log.d(TAG, "abd 找不到点击控件:" + id + "," + tv);
            }
        }
    }, delay);
}

 

使用dispatchGesture()