简述Android 无障碍服务-微信自动化

实现自动化服务分几步?

  • 步骤一:准备工具
    • UI Automator
      • 获取节点的信息
  • 步骤二:编写代码
    • AccessibilityService
      • 对指定页面进行操作

撸代码

  • 首先创建服务

      public class AppAccessibilityService extends AccessibilityService {
          
          private static final String TAG = AppAccessibilityService.class.getSimpleName();
          
          // 保存当前实例,后面可以通过服务获取 AccessibilityNodeInfo
          private static AppAccessibilityService mService;
          
          @Override
          protected void onServiceConnected() {
              super.onServiceConnected();
              mService = this;
          }
    
           @Override
          public void onAccessibilityEvent(AccessibilityEvent event) {
    
              // 获取当前整个活动窗口的根节点
              AccessibilityNodeInfo rootNode = getRootInActiveWindow();
    
              // 获取事件类型,在对应的事件类型中对相应的节点进行操作
              int eventType = event.getEventType();
              switch (eventType) {
                  case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 
                      LogUtil.d(TAG, "界面改变::PackageName::" + event.getPackageName() + "::ClassName::" + event.getClassName());
                      // 获取父节点
                      rootNode.getParent();
                      // 获取子节点
                      rootNode.getChild(0);
                      // 在节点上执行一个动作,通过返回值判断是否执行成功
                      boolean bool = rootNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                      bool = nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
                      bool = rootNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
                      // 通过字符串查找节点元素
                      rootNode.findAccessibilityNodeInfosByText("");
                      // 通过视图id查找节点元素
                      rootNode.findAccessibilityNodeInfosByViewId("");
                      break;
                  case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                      LogUtil.d(TAG, "内容改变::PackageName::" + event.getPackageName() + "::ClassName::" + event.getClassName());
                      break;
                  case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                      LogUtil.d(TAG, "滑动变化::PackageName::" + event.getPackageName() + "::ClassName::" + event.getClassName());
                      break;
                  default:
                      break;
              }
          }
    
          @Override
          public void onDestroy() {
              super.onDestroy();
              mService = null;
          }
      }
    
  • 编写accessibility_config.xml文件

      
      
    
  • 在manifest.xml注册服务

      
          
              
          
    
          
      
    
  • 通过上面代码,已经能实现一些简单的操作啦

常见问题

  • 节点无法点击
    • 解决方法,使用模拟坐标点击

        public static boolean performClick(AccessibilityService service, AccessibilityNodeInfo nodeInfo) {
      
            if (service == null || nodeInfo == null) {
                return false;
            }
      
            Rect rect = new Rect();
            nodeInfo.getBoundsInScreen(rect);
            int x = (rect.left + rect.right) / 2;
            int y = (rect.top + rect.bottom) / 2;
      
            Point point = new Point(x, y);
            GestureDescription.Builder builder = new GestureDescription.Builder();
            Path path = new Path();
            path.moveTo(point.x, point.y);
            builder.addStroke(new GestureDescription.StrokeDescription(path, 0L, 100L));
            GestureDescription gesture = builder.build();
      
            boolean isDispatched = service.dispatchGesture(gesture, new AccessibilityService.GestureResultCallback() {
                @Override
                public void onCompleted(GestureDescription gestureDescription) {
                    super.onCompleted(gestureDescription);
                    LogUtil.d(TAG, "dispatchGesture onCompleted: 完成...");
                }
      
                @Override
                public void onCancelled(GestureDescription gestureDescription) {
                    super.onCancelled(gestureDescription);
                    LogUtil.d(TAG, "dispatchGesture onCancelled: 取消...");
                }
            }, null);
      
            return isDispatched;
        }
      
  • 界面事件无响应
    • 解决方法,使用超时处理机制
      • 建立一个定时器,去判断当前界面是否超时,然后进行超时处理(判断当前位于哪个界面,获取根节点,模拟操作)
  • 事件响应重复,导致方法执行多次
    • 解决方法,使用延迟
      • 触发了事件后,使用Handler进行延迟处理,等待事件都响应完后,主动获取根节点,模拟操作

你可能感兴趣的:(简述Android 无障碍服务-微信自动化)