當我們把輔助許可權玩的比較熟悉 的時候,就可以釋放我們的雙手做一些有趣的事情了,例如之前網上流傳的微信自動搶紅包外掛,就是使用的這個服務,不過我們今兒講的是微信自動評論與點贊功能(搶紅包的文章網上已經有比較多)。
一、懸浮窗配置
關於懸浮窗的詳細配置,請看我另一篇博文,這裡不再贅述,「傳送門」:
二、自動化邏輯程式碼實現
說明:我們通過 Monitor 工具,取到的節點 id ,在微信的每個版本是不一樣的 (微信動態生成節點 id,我是通過伺服器後臺對不同的微信版本,維護一份 id 配置,根據請求的微信版本,返回對應得 id 值),所以本文以微信 v6.7.2 的版本作為例子,如下程式碼可作參考。
這裡只是提供了微信自動點贊與自動評論的示例,當然本人也寫了類似於微信自動加好友,自動加附近的人,檢測死粉的功能,釘釘自動打卡… 這裡只是拋轉引玉,大家根據我提供的思路,去實現,由於原始碼涉及伺服器相關操作,不太方便開源,
{
"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"
} ]
}複製程式碼
1、微信朋友圈自動點贊
效果如圖(希望我朋友不會打我,這裡就不視訊打碼了,┭┮﹏┭┮),這裡面的懸浮窗可以有效阻擋使用者操作,只有點選停止之後,才能操作微信介面。
/** * 朋友圈點贊 * Created by czc on 2018/8/23. */public class LikeStrategy extends BaseStrategy {
@Override protected boolean handleEvent() {
/** * 匹配每個介面,根據當前介面執行相關操作 * 1、在微信首頁點選【發現】按鈕 * 2、然後點選【朋友圈】,進入朋友圈介面 * 3、滾動朋友圈【動態列表】,對每個動態進行點贊 */ 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);
}
}
}
}
}
}複製程式碼
2、微信朋友圈自動評論
效果如圖
/** * 朋友圈評論 * Created by czc on 2018/8/23. */public class CommentStrategy extends BaseStrategy {
@Override protected boolean handleEvent() {
/** * 匹配每個介面,根據當前介面執行相關操作 * 1、在微信首頁點選【發現】按鈕 * 2、然後點選【朋友圈】,進入朋友圈介面 * 3、滾動朋友圈【動態列表】,對每個動態進行評論 */ 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);
}
}
}
}
}
}複製程式碼
3、相關工具類
工具類裡面的程式碼是自己封裝的,不一定都適用,工具類可能存在不足與缺陷,為什麼執行操作需要 Sleep 1s ,因為太快的話,有些介面的節點資訊還沒更新出來,會導致點選失敗等情況:
/** * 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 的手機,我們可以通過輔助許可權找到該節點在螢幕上的位置,並獲取中心點:
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);
複製程式碼
更多技術分享,請加微信公眾號——碼農茅草屋: