Android輔助服務之微信自動評論與點贊

當咱們把輔助權限玩的比較熟悉 的時候,就能夠釋放咱們的雙手作一些有趣的事情了,例如以前網上流傳的微信自動搶紅包插件,就是使用的這個服務,不過咱們今兒講的是微信自動評論與點贊功能(搶紅包的文章網上已經有比較多)。node

1、懸浮窗配置

關於懸浮窗的詳細配置,請看我另外一篇博文,這裏再也不贅述,「傳送門」:android

Android 輔助權限與懸浮窗服務器

2、自動化邏輯代碼實現

說明:咱們經過 Monitor 工具,取到的節點 id ,在微信的每一個版本是不同的 (微信動態生成節點 id,我是經過服務器後臺對不一樣的微信版本,維護一份 id 配置,根據請求的微信版本,返回對應得 id 值),因此本文以微信 v6.7.2 的版本做爲例子,以下代碼可做參考。微信

這裏只是提供了微信自動點贊與自動評論的示例,固然本人也寫了相似於微信自動加好友,自動加附近的人,檢測死粉的功能,釘釘自動打卡... 這裏只是拋轉引玉,你們根據我提供的思路,去實現,因爲源碼涉及服務器相關操做,不太方便開源,markdown

{
    "tasks": [
        {
            "nodes": [
                {
                    "action": "scrllor", 
                    "className": "android.widget.ListView", 
                    "id": "com.tencent.mm:id/cno", 
                    "key": "nearHumanList", 
                    "text": "@附近的人列表"
                }, 
                {
                    "className": "android.widget.TextView", 
                    "id": "com.tencent.mm:id/b3i", 
                    "key": "nearHumanListName", 
                    "text": "@附近的人列表名字"
                }, 
                {
                    "className": "android.widget.TextView", 
                    "id": "com.tencent.mm:id/sm", 
                    "key": "detailName", 
                    "text": "@附近的人詳情名字"
                }, 
                {
                    "className": "android.widget.ListView", 
                    "id": "com.tencent.mm:id/bcs", 
                    "key": "phoneHumanList", 
                    "text": "@手機聯繫人列表"
                }, 
                {
                    "className": "android.widget.TextView", 
                    "id": "com.tencent.mm:id/bgl", 
                    "key": "phoneHumanListName", 
                    "text": "@手機聯繫人列表名字"
                }, 
                {
                    "className": "android.widget.TextView", 
                    "id": "com.tencent.mm:id/bgm", 
                    "key": "phoneHumanListAccount", 
                    "text": "@手機聯繫人列表暱稱"
                }, 
                {
                    "className": "android.widget.TextView", 
                    "id": "com.tencent.mm:id/sm", 
                    "key": "phoneHumandetailName", 
                    "text": "@手機聯繫人詳情名字"
                }, 
                {
                    "className": "android.widget.ListView",
                    "id": "com.tencent.mm:id/doq",
                    "key": "momentList",
                    "text": "@朋友圈列表"
                }
            ],
            "pages": [ ],
            "taskName": "微信腳本",
            "version": "6.7.2"
        }
    ]
}
複製代碼

一、微信朋友圈自動點贊

效果如圖(但願我朋友不會打我,這裏就不視頻打碼了,┭┮﹏┭┮),這裏面的懸浮窗能夠有效阻擋用戶操做,只有點擊中止以後,才能操做微信界面。ide

在這裏插入圖片描述

/**
 * 朋友圈點贊
 * Created by czc on 2018/8/23.
 */
public class LikeStrategy extends BaseStrategy {

    @Override
    protected boolean handleEvent() {
        /**
         * 匹配每一個界面,根據當前界面執行相關操做
         * 一、在微信首頁點擊【發現】按鈕
         * 二、而後點擊【朋友圈】,進入朋友圈界面
         * 三、滾動朋友圈【動態列表】,對每一個動態進行點贊
         */
        if (matchPage(Page.LauncherUI) || matchPage(Page.WxViewPager)) {
            clickFindBtn(getRoot());
            clickCommentTv(getRoot());
        } else if (checkWxScroller(Page.SnsTimeLineUI)) {
            scrollerList(getRoot());
        } else if (matchPage(Page.BaseP)) {

        } else {
            return false;
        }
        return true;
    }


    private void clickFindBtn(AccessibilityNodeInfo root) {
        NodeUtil.findNodeByTextAndClick(root, "發現");
    }

    private void clickCommentTv(AccessibilityNodeInfo root) {
        NodeUtil.findNodeByTextAndClick(root, "朋友圈");
    }


    private void scrollerList(AccessibilityNodeInfo root) {
        //這裏的滾動控件對應於朋友圈動態的 ListView 
        AccessibilityNodeInfo scrollerNode = findNodeByTaskNode(root, getNode("momentList"));
        if (scrollerNode == null) {
            Log.e(TAG, "scroller is null");
            return;
        }
        if (scrollerNode != null) {
            final int count = scrollerNode.getChildCount();
            for (int i = 0; i < count; i++) {
                AccessibilityNodeInfo child = scrollerNode.getChild(i);
                if (child != null && child.isVisibleToUser()) {
                    AccessibilityNodeInfo commentNode = NodeUtil.findNodeByFilter(child, new NodeUtil.NodeFilter() {
                        @Override
                        public String text() {
                            return "評論";
                        }

                        @Override
                        public boolean filter(AccessibilityNodeInfo node) {
                            return node.getClassName() != null && node.getClassName().equals(NodeUtil.IMAGE_VIEW)
                                    && node.getContentDescription() != null && node.getContentDescription().toString().equals("評論");
                        }
                    });
                    if (commentNode != null && commentNode.isVisibleToUser()) {
                        NodeUtil.performClick(commentNode);
                        NodeUtil.findNodeByFilterAndClick(root, new NodeUtil.NodeFilter() {
                            @Override
                            public String text() {
                                return "贊";
                            }

                            @Override
                            public boolean filter(AccessibilityNodeInfo node) {
                                return node.getClassName() != null && node.getClassName().equals(NodeUtil.TEXT_VIEW)
                                        && node.getText() != null && node.getText().toString().equals("贊");
                            }
                        });
                    }
                }
                //可見的最後一個 item 
                if (i == count - 1) {
                    //滾動控件是否能夠滾動
                    if (scrollerNode.isScrollable()) {
                        NodeUtil.findNodeByFilterAndClick(root, new NodeUtil.NodeFilter() {
                            @Override
                            public String text() {
                                return "評論";
                            }

                            @Override
                            public boolean filter(AccessibilityNodeInfo node) {
                                return node.getClassName() != null && node.getClassName().equals(NodeUtil.TEXT_VIEW)
                                        && node.getText() != null && node.getText().toString().equals("評論");
                            }
                        });
                        
                        //循環滾動
                        performScroll(scrollerNode);
                    }
                }
            }
        }
    }
}
複製代碼

二、微信朋友圈自動評論

效果如圖工具

在這裏插入圖片描述

/**
 * 朋友圈評論
 * Created by czc on 2018/8/23.
 */
public class CommentStrategy extends BaseStrategy {

    @Override
    protected boolean handleEvent() {
        /**
         * 匹配每一個界面,根據當前界面執行相關操做
         * 一、在微信首頁點擊【發現】按鈕
         * 二、而後點擊【朋友圈】,進入朋友圈界面
         * 三、滾動朋友圈【動態列表】,對每一個動態進行評論
         */
        if (matchPage(Page.LauncherUI) || matchPage(Page.WxViewPager)) {
            clickFindBtn(getRoot());
            clickCommentTv(getRoot());
        } else if (checkWxScroller(Page.SnsTimeLineUI)) {
            scrollerList(getRoot());
        } else if (matchPage(Page.BaseP)) {

        } else {
            return false;
        }
        return true;
    }


    private void clickFindBtn(AccessibilityNodeInfo root) {
        NodeUtil.findNodeByTextAndClick(root, "發現");
    }

    private void clickCommentTv(AccessibilityNodeInfo root) {
        NodeUtil.findNodeByTextAndClick(root, "朋友圈");
    }


    private void scrollerList(AccessibilityNodeInfo root) {
        AccessibilityNodeInfo scrollerNode = findNodeByTaskNode(root, getNode("momentList"));
        if (scrollerNode == null) {
            Log.e(TAG, "scroller is null");
            return;
        }
        if (scrollerNode != null) {
            final int count = scrollerNode.getChildCount();
            for (int i = 0; i < count; i++) {
                AccessibilityNodeInfo child = scrollerNode.getChild(i);
                if (child != null && child.isVisibleToUser()) {
                    AccessibilityNodeInfo commentNode = NodeUtil.findNodeByFilter(child, new NodeUtil.NodeFilter() {
                        @Override
                        public String text() {
                            return "評論";
                        }

                        @Override
                        public boolean filter(AccessibilityNodeInfo node) {
                            return node.getClassName() != null && node.getClassName().equals(NodeUtil.IMAGE_VIEW)
                                    && node.getContentDescription() != null && node.getContentDescription().toString().equals("評論");
                        }
                    });
                    if (commentNode != null && commentNode.isVisibleToUser()) {
                        NodeUtil.performClick(commentNode);
                        NodeUtil.findNodeByFilterAndClick(root, new NodeUtil.NodeFilter() {
                            @Override
                            public String text() {
                                return "評論";
                            }

                            @Override
                            public boolean filter(AccessibilityNodeInfo node) {
                                return node.getClassName() != null && node.getClassName().equals(NodeUtil.TEXT_VIEW)
                                        && node.getText() != null && node.getText().toString().equals("評論");
                            }
                        });

                        AccessibilityNodeInfo editNode = NodeUtil.findNodeByFilter(child, new NodeUtil.NodeFilter() {
                            @Override
                            public String text() {
                                return "評論";
                            }

                            @Override
                            public boolean filter(AccessibilityNodeInfo node) {
                                return node.getClassName() != null && node.getClassName().equals(NodeUtil.EDIT_TEXT)
                                        && node.getText() != null && node.getText().toString().equals("評論");
                            }
                        });
                        if (editNode == null) {
                            if (root != null) {
                                editNode = root.findFocus(AccessibilityNodeInfo.FOCUS_INPUT);
                            }
                        }
                        if (editNode != null) {
                            //輸入自定義評論內容
                            NodeUtil.performPaste(editNode, "東西不錯哦~");
                            //點擊【發送】
                            NodeUtil.findNodeByTextAndClick(root, "發送");
                        }
                    }
                }
                if (i == count - 1) {
                    if (scrollerNode.isScrollable()) {
                        performScroll(scrollerNode);
                    }
                }
            }
        }
    }
}
複製代碼

三、相關工具類

工具類裏面的代碼是本身封裝的,不必定都適用,工具類可能存在不足與缺陷,爲何執行操做須要 Sleep 1s ,由於太快的話,有些界面的節點信息還沒更新出來,會致使點擊失敗等狀況:post

/**
 * Created by czc on 2017/7/3.
 */
public class NodeUtil {
	private static final String TAG = "NodeUtil";
	private static final int millis = 1000;

	public static final String LIST_VIEW = "android.widget.ListView";
	public static final String ABS_LIST_VIEW = "android.widget.AbsListView";
	public static final String SCROLL_VIEW = "android.widget.ScrollView";
	public static final String TEXT_VIEW = "android.widget.TextView";
	public static final String BUTTON = "android.widget.Button";
	public static final String VIEW = "android.view.View";
	public static final String IMAGE_VIEW = "android.widget.ImageView";
    public static final String IMAGE_BUTTON = "android.widget.ImageButton";
    public static final String GRID_VIEW = "android.widget.GridView";
	public static final String EDIT_TEXT = "android.widget.EditText";
	public static final String RELATIVE_LAYOUT = "android.widget.RelativeLayout";
	public static final String LINEAR_LAYOUT = "android.widget.LinearLayout";
    public static final String LINEAR_LAYOUT_COMPAT = "android.support.v7.widget.LinearLayoutCompat";

	public static void sleep(long times) {
		try {
			Thread.sleep(times);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static boolean checkNodeText(AccessibilityNodeInfo nodeInfo) {
		if (nodeInfo == null) {
			return false;
		}
		return !StringUtil.isEmpty(nodeInfo.getText().toString());
	}

	public static boolean checkNodeDes(AccessibilityNodeInfo nodeInfo) {
		if (nodeInfo == null) {
			return false;
		}
		return !StringUtil.isEmpty(nodeInfo.getContentDescription());
	}

	public static boolean performClick(AccessibilityNodeInfo node) {
		AccessibilityNodeInfo clickNode = node;
		if (clickNode == null) {
			return false;
		}
		while (clickNode != null
				&& !clickNode.isClickable()) {
			clickNode = clickNode.getParent();
		}
		if (clickNode != null) {
			boolean result = clickNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
			sleep();
			return result;
		}
		Log.e(TAG, "clickNode is null");
		return false;
	}

    // root下,經過 adb 命令執行點擊
	public static boolean performShellClick(AccessibilityNodeInfo node) {
		AccessibilityNodeInfo clickNode = node;
		if (clickNode == null) {
			return false;
		}
		Rect r = new Rect();
		node.getBoundsInScreen(r);
		if (r.centerX() > ScreenUtils.getScreenWidth(OttUtil.get().getApp())
				|| r.centerY() > ScreenUtils.getScreenHeight(OttUtil.get().getApp())
				|| r.centerX() <= 0
				|| r.centerY() <= 0) {
			return false;
		}
		String cmd = String.format("input tap %d %d", r.centerX(), r.centerY());
		ShellUtils.CommandResult commandResult = ShellUtils.execCmd(cmd, true);
		sleep();
		return commandResult.result != -1;
	}

    // root下,經過 adb 命令執行長按
	public static boolean performShellLongClick(AccessibilityNodeInfo node, long time) {
		AccessibilityNodeInfo clickNode = node;
		if (clickNode == null) {
			return false;
		}
		Rect r = new Rect();
		clickNode.getBoundsInScreen(r);
		int x = r.centerX();
		int y = r.centerY();
		String cmd = String.format("input swipe %d %d %d %d %d", x, y, x, y, time);
		ShellUtils.CommandResult commandResult = ShellUtils.execCmd(cmd, true);
		NodeUtil.sleep(time);
		return commandResult.result != -1;
	}

    // root下,經過 adb 命令執行滾動
    public static boolean performShellScroll() {
        int screenWidth = ScreenUtils.getScreenWidth(OttUtil.get().getApp());
        int screenHeight = ScreenUtils.getScreenHeight(OttUtil.get().getApp());
        String cmd = String.format("input swipe %d %d %d %d %d", screenWidth / 2, (int) (screenHeight * (3 * 1.0f / 5)),screenWidth / 2, screenHeight / 5,  1500L);
        ShellUtils.CommandResult commandResult = ShellUtils.execCmd(cmd, true);
        NodeUtil.sleep(500);
        return commandResult.result != -1;
    }


	public static boolean performScroll(AccessibilityNodeInfo scrollerNode) {
		while (scrollerNode != null && !scrollerNode.isScrollable()) {
			scrollerNode = scrollerNode.getParent();
		}
		if (scrollerNode != null) {
			boolean result = scrollerNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
			sleep();
			return result;
		}
		Log.e(TAG, "scrollerNode is null");
		return false;
	}

	public static boolean performScrollBack(AccessibilityNodeInfo scrollerNode) {
		while (scrollerNode != null && !scrollerNode.isScrollable()) {
			scrollerNode = scrollerNode.getParent();
		}
		if (scrollerNode != null) {
			boolean result = scrollerNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
			sleep();
			return result;
		}
		return false;
	}

    /**
     *  執行粘貼操做(注意:執行以後,會 sleep 1s)
     * @param ct
     * @param node
     * @param text
     * @return
     */
	public static boolean performPaste(Context ct, AccessibilityNodeInfo node, String text) {
		if (node == null || StringUtil.isEmpty(text)) {
			return false;
		}
		boolean result;
		if (Build.VERSION.SDK_INT >= 21) {
			Bundle arguments = new Bundle();
			arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
			result = node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
			sleep();
			return result;
		} else {
			ClipboardManager cm = (ClipboardManager) ct.getSystemService(Context.CLIPBOARD_SERVICE);
			ClipData mClipData = ClipData.newPlainText("text", text);
			cm.setPrimaryClip(mClipData);
			result = node.performAction(AccessibilityNodeInfo.ACTION_PASTE);
			sleep();
			return result;
		}
	}

	public static boolean hasNode(AccessibilityNodeInfo root, String text) {
		if (root == null || StringUtil.isEmpty(text)) {
			return false;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return false;
		}
		return true;
	}

	public static AccessibilityNodeInfo findNodeByFilter(AccessibilityNodeInfo root, String text, NodeFilter filter) {
		if (root == null || StringUtil.isEmpty(text)) {
			return null;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return null;
		}
		AccessibilityNodeInfo clickNode = null;
		for (AccessibilityNodeInfo nodeInfo : nodeList) {
			if (filter.filter(nodeInfo)) {
				clickNode = nodeInfo;
				break;
			}
		}
		return clickNode;
	}
	   public static AccessibilityNodeInfo findNodeByFilter(AccessibilityNodeInfo root, NodeTextFilter filter) {
        if (root == null || filter == null || StringUtil.isEmpty(filter.fiterText())) {
            return null;
        }
        List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(filter.fiterText());

        if (nodeList == null || nodeList.isEmpty()) {
            return null;
        }
        AccessibilityNodeInfo clickNode = null;
        for (AccessibilityNodeInfo nodeInfo : nodeList) {
            if (filter.filter(nodeInfo)) {
                clickNode = nodeInfo;
                break;
            }
        }
        return clickNode;
    }

    public static AccessibilityNodeInfo findNodeByFilter(AccessibilityNodeInfo root, NodeIdFilter filter) {
        if (root == null || filter == null || StringUtil.isEmpty(filter.fiterViewId())) {
            return null;
        }
        List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByViewId(filter.fiterViewId());

        if (nodeList == null || nodeList.isEmpty()) {
            return null;
        }
        AccessibilityNodeInfo clickNode = null;
        for (AccessibilityNodeInfo nodeInfo : nodeList) {
            if (filter.filter(nodeInfo)) {
                clickNode = nodeInfo;
                break;
            }
        }
        return clickNode;
    }


	public static AccessibilityNodeInfo findNodeByText(AccessibilityNodeInfo root, String text) {
		if (root == null || StringUtil.isEmpty(text)) {
			return null;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return null;
		}
		AccessibilityNodeInfo clickNode = null;
		for (AccessibilityNodeInfo nodeInfo : nodeList) {
			boolean eqText = nodeInfo.getText() != null && nodeInfo.getText().toString().equals(text);
			boolean eqDesc = nodeInfo.getContentDescription() != null && nodeInfo.getContentDescription().toString().equals(text);
			if (eqText || eqDesc) {
				clickNode = nodeInfo;
				break;
			}
		}
		return clickNode;
	}

	public static AccessibilityNodeInfo findNodeContainsText(AccessibilityNodeInfo root, String text) {
		if (root == null || StringUtil.isEmpty(text)) {
			return null;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return null;
		}
		AccessibilityNodeInfo clickNode = null;
		for (AccessibilityNodeInfo nodeInfo : nodeList) {
			boolean eqText = nodeInfo.getText() != null && nodeInfo.getText().toString().contains(text);
			boolean eqDesc = nodeInfo.getContentDescription() != null && nodeInfo.getContentDescription().toString().contains(text);
			if (eqText || eqDesc) {
				clickNode = nodeInfo;
				break;
			}
		}
		return clickNode;
	}

	public static boolean findNodeByTextAndClick(AccessibilityNodeInfo root, String text) {
		if (root == null || StringUtil.isEmpty(text)) {
			return false;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return false;
		}
		AccessibilityNodeInfo clickNode = null;
		for (AccessibilityNodeInfo nodeInfo : nodeList) {
			boolean eqText = nodeInfo.getText() != null && nodeInfo.getText().toString().equals(text);
			boolean eqDesc = nodeInfo.getContentDescription() != null && nodeInfo.getContentDescription().toString().equals(text);
			if (eqText || eqDesc) {
				clickNode = nodeInfo;
				break;
			}
		}
		return performClick(clickNode);
	}

	public static boolean findNodeByIdAndClick(AccessibilityNodeInfo root, String id) {
		if (root == null || StringUtil.isEmpty(id)) {
			return false;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByViewId(id);

		if (nodeList == null || nodeList.isEmpty()) {
			return false;
		}
		return performClick(nodeList.get(0));
	}

	public static boolean findNodeContainsTextAndClick(AccessibilityNodeInfo root, String text) {
		if (root == null || StringUtil.isEmpty(text)) {
			return false;
		}
		List<AccessibilityNodeInfo> nodeList = root.findAccessibilityNodeInfosByText(text);

		if (nodeList == null || nodeList.isEmpty()) {
			return false;
		}
		AccessibilityNodeInfo clickNode = null;
		for (AccessibilityNodeInfo nodeInfo : nodeList) {
			boolean eqText = nodeInfo.getText() != null && nodeInfo.getText().toString().contains(text);
			boolean eqDesc = nodeInfo.getContentDescription() != null && nodeInfo.getContentDescription().toString().contains(text);
			if (eqText || eqDesc) {
				clickNode = nodeInfo;
				break;
			}
		}
		Log.i(TAG, "點擊:"+text+"!");
		return performClick(clickNode);
	}

	public static boolean findNodeByIdTextAndClick(AccessibilityNodeInfo root, String id, String text, boolean isNewPage) {
		AccessibilityNodeInfo clickNode = findNodeByIdAndText(root, id, text);
		if (clickNode == null) {
			return false;
		}
		return performClick(clickNode);
	}

	public static boolean findNodeByIdClassAndClick(AccessibilityNodeInfo root, String id, String className, boolean isNewPage) {
		AccessibilityNodeInfo clickNode = findNodeByIdAndClassName(root, id, className);
		if (clickNode == null) {
			return false;
		}
		return performClick(clickNode);
	}


	public static AccessibilityNodeInfo findNodeByIdAndClassName(AccessibilityNodeInfo root, String id, String className) {
		if (root == null) {
			return null;
		}
		List<AccessibilityNodeInfo> idNodeInfoList = root.findAccessibilityNodeInfosByViewId(id);
		if (idNodeInfoList == null || idNodeInfoList.isEmpty()) {
			return null;
		}
		for (int i = 0; i < idNodeInfoList.size(); i++) {
			AccessibilityNodeInfo nodeInfo = idNodeInfoList.get(i);
			if (nodeInfo == null) {
				continue;
			}
			//根據className過濾
			if (!StringUtil.isEmpty(className)) {
				if (className.equals(nodeInfo.getClassName())) {
					return nodeInfo;
				}
			}
		}
		return null;
	}

	public static AccessibilityNodeInfo findNodeByTextAndClass(AccessibilityNodeInfo root, String text, String clazz) {
		if (root == null) {
			return null;
		}
		List<AccessibilityNodeInfo> idNodeInfoList = root.findAccessibilityNodeInfosByText(text);
		if (idNodeInfoList == null || idNodeInfoList.isEmpty()) {
			return null;
		}

		AccessibilityNodeInfo clickNode = null;
		for (int i = 0; i < idNodeInfoList.size(); i++) {
			AccessibilityNodeInfo nodeInfo = idNodeInfoList.get(i);
			if (nodeInfo == null) {
				continue;
			}
			//根據class過濾
			if (!StringUtil.isEmpty(clazz)) {
				if (clazz.equals(nodeInfo.getClassName().toString())) {
					clickNode = nodeInfo;
					break;
				}
			}
		}
		if (clickNode == null) {
			return null;
		}
		return clickNode;
	}

	public static AccessibilityNodeInfo findNodeByIdAndText(AccessibilityNodeInfo root, String id, String text) {
		if (root == null) {
			return null;
		}
		List<AccessibilityNodeInfo> idNodeInfoList = root.findAccessibilityNodeInfosByViewId(id);
		if (idNodeInfoList == null || idNodeInfoList.isEmpty()) {
			return null;
		}

		AccessibilityNodeInfo clickNode = null;
		for (int i = 0; i < idNodeInfoList.size(); i++) {
			AccessibilityNodeInfo nodeInfo = idNodeInfoList.get(i);
			if (nodeInfo == null) {
				continue;
			}
			//根據text過濾
			if (!StringUtil.isEmpty(nodeInfo.getText())
					&& !StringUtil.isEmpty(text)) {
				if (text.equals(nodeInfo.getText())) {
					clickNode = nodeInfo;
					break;
				}
			}
		}
		if (clickNode == null) {
			return null;
		}
		return clickNode;
	}

	/**
	 * @param root
	 * @param id
	 * @param className
	 * @return
	 */
	public static List<AccessibilityNodeInfo> findNodeByIdAndClassNameList(AccessibilityNodeInfo root, String id, String className) {
		if (root == null) {
			return null;
		}
		List<AccessibilityNodeInfo> resultList = new ArrayList<>();
		List<AccessibilityNodeInfo> idNodeInfoList = root.findAccessibilityNodeInfosByViewId(id);
		if (idNodeInfoList == null || idNodeInfoList.isEmpty()) {
			return null;
		}
		for (int i = 0; i < idNodeInfoList.size(); i++) {
			AccessibilityNodeInfo nodeInfo = idNodeInfoList.get(i);
			if (nodeInfo == null) {
				continue;
			}
			//根據className過濾
			if (!StringUtil.isEmpty(className)) {
				if (className.equals(nodeInfo.getClassName())) {
					resultList.add(nodeInfo);
				}
			}
		}
		return resultList;
	}

	public static AccessibilityNodeInfo findNodeByClass(AccessibilityNodeInfo root, String className) {
		if (TextUtils.isEmpty(className) || root == null) {
			return null;
		}
		int childCount = root.getChildCount();
		for (int i = 0; i < childCount; i++) {
			AccessibilityNodeInfo rootChild = root.getChild(i);
			if (rootChild != null) {
				if (className.equals(rootChild.getClassName().toString().trim())) {
					return rootChild;
				}
			}
		}
		return null;
	}

	public static List<AccessibilityNodeInfo> findNodeByClassList(AccessibilityNodeInfo root, String className) {
		List<AccessibilityNodeInfo> list = new ArrayList<>();
		if (TextUtils.isEmpty(className) || root == null) {
			return Collections.EMPTY_LIST;
		}
		int childCount = root.getChildCount();
		for (int i = 0; i < childCount; i++) {
			AccessibilityNodeInfo rootChild = root.getChild(i);
			if (rootChild != null) {
				if (className.equals(rootChild.getClassName().toString().trim())) {
					list.add(rootChild);
				}
			}
		}
		return list;
	}

	public static List<AccessibilityNodeInfo> traverseNodefilterByDesc(AccessibilityNodeInfo root, final String desc) {
		if (TextUtils.isEmpty(desc) || root == null) {
			return null;
		}
		List<AccessibilityNodeInfo> list = new ArrayList<>();
		traverseNodeClassToList(root, list, new NodeFilter() {
			@Override
			public boolean filter(AccessibilityNodeInfo node) {
				return node.getContentDescription() != null && desc.equals(node.getContentDescription().toString());
			}
		});
		return list;
	}

	public static List<AccessibilityNodeInfo> traverseNodeByClassName(AccessibilityNodeInfo root, final String className) {
		if (TextUtils.isEmpty(className) || root == null) {
			return Collections.EMPTY_LIST;
		}
		List<AccessibilityNodeInfo> list = new ArrayList<>();
		traverseNodeClassToList(root, list, new NodeFilter() {
			@Override
			public boolean filter(AccessibilityNodeInfo node) {
				return node.getClassName() != null && className.equals(node.getClassName().toString());
			}
		});
		return list;
	}

	private static void traverseNodeClassToList(AccessibilityNodeInfo node, List<AccessibilityNodeInfo> list, NodeFilter filter) {
		if (node == null || node.getChildCount() == 0) {
			return;
		}
		for (int i = 0; i < node.getChildCount(); i++) {
			AccessibilityNodeInfo child = node.getChild(i);
			if (child != null) {
				if (filter.filter(child)) {
					list.add(child);
				}
				if (child.getChildCount() > 0) {
					traverseNodeClassToList(child, list, filter);
				}
			}
		}
	}

	public interface NodeFilter {
		boolean filter(AccessibilityNodeInfo node);
	}

	public interface NodeTextFilter extends NodeFilter {
        String fiterText();
    }

    public interface NodeIdFilter extends NodeFilter {
        String fiterViewId();
    }
}

複製代碼

在部分 Root 的手機,咱們能夠經過輔助權限找到該節點在屏幕上的位置,並獲取中心點:ui

Rect r = new Rect();
node.getBoundsInScreen(r);
if (r.centerX() > ScreenUtils.getScreenWidth(OttUtil.get().getApp())
		|| r.centerY() > ScreenUtils.getScreenHeight(OttUtil.get().getApp())
		|| r.centerX() <= 0
		|| r.centerY() <= 0) {
	return false;
}
String cmd = String.format("input tap %d %d", r.centerX(), r.centerY());
複製代碼

再去執行相關操做:spa

ShellUtils.CommandResult commandResult = ShellUtils.execCmd(cmd, true);
複製代碼
相關文章
相關標籤/搜索