first blood

This commit is contained in:
2026-01-26 14:23:13 +08:00
parent 1634953750
commit ee72a1fb3e
9 changed files with 575 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
package com.rnbot;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.graphics.Path;
import android.os.Bundle;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import java.util.ArrayList;
import java.util.List;
public class RNBotAccessibilityService extends AccessibilityService {
private static RNBotAccessibilityService instance;
public static RNBotAccessibilityService getInstance() {
return instance;
}
public static boolean isServiceRunning() {
return instance != null;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// 可以在这里监听各种事件
}
@Override
public void onInterrupt() {
// 服务中断
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
instance = this;
}
@Override
public void onDestroy() {
super.onDestroy();
instance = null;
}
public List<AccessibilityNodeInfo> findNodesByType(String type, String value) {
List<AccessibilityNodeInfo> result = new ArrayList<>();
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) return result;
switch (type) {
case "id":
findNodesByIdRecursive(root, value, result);
break;
case "text":
findNodesByTextRecursive(root, value, result);
break;
case "name":
findNodesByNameRecursive(root, value, result);
break;
case "className":
findNodesByClassNameRecursive(root, value, result);
break;
}
return result;
}
private void findNodesByIdRecursive(AccessibilityNodeInfo node, String resId, List<AccessibilityNodeInfo> result) {
if (node == null) return;
String id = node.getViewIdResourceName();
if (id != null && id.equals(resId)) {
result.add(node);
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo child = node.getChild(i);
if (child != null) {
findNodesByIdRecursive(child, resId, result);
}
}
}
private void findNodesByTextRecursive(AccessibilityNodeInfo node, String text, List<AccessibilityNodeInfo> result) {
if (node == null) return;
CharSequence nodeText = node.getText();
if (nodeText != null && nodeText.toString().contains(text)) {
result.add(node);
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo child = node.getChild(i);
if (child != null) {
findNodesByTextRecursive(child, text, result);
}
}
}
private void findNodesByNameRecursive(AccessibilityNodeInfo node, String name, List<AccessibilityNodeInfo> result) {
if (node == null) return;
CharSequence desc = node.getContentDescription();
if (desc != null && desc.toString().contains(name)) {
result.add(node);
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo child = node.getChild(i);
if (child != null) {
findNodesByNameRecursive(child, name, result);
}
}
}
private void findNodesByClassNameRecursive(AccessibilityNodeInfo node, String className, List<AccessibilityNodeInfo> result) {
if (node == null) return;
CharSequence cls = node.getClassName();
if (cls != null && cls.toString().equals(className)) {
result.add(node);
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo child = node.getChild(i);
if (child != null) {
findNodesByClassNameRecursive(child, className, result);
}
}
}
public boolean clickAt(int x, int y) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.N) {
return false;
}
Path path = new Path();
path.moveTo(x, y);
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription gesture = builder
.addStroke(new GestureDescription.StrokeDescription(path, 0, 50))
.build();
return dispatchGesture(gesture, null, null);
}
public boolean setTextById(String resId, String text) {
List<AccessibilityNodeInfo> nodes = findNodesByType("id", resId);
if (nodes.isEmpty()) return false;
AccessibilityNodeInfo node = nodes.get(0);
if (!node.isEditable()) return false;
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
return node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
}
}