使用AccessibilityService实现自动遍历点赞功能

作者:化作孤岛的瓜 时间:2023-10-18 16:22:53 

概述:

利用AccessibilityService机制实现了一个比较好玩儿的功能,微信朋友圈自动遍历点赞。即通过不断的滚动+点赞实现把每一条朋友圈都赞一次。

当然其中还要涉及一些判断算法,比如如果这条朋友圈已经赞过就跳过去,以及当前界面没有可赞的朋友圈时执行翻页。其实做起来试错是个很繁冗的过程,这个效果也差不多做了两天。

使用方式:

运行程序-开启无障碍服务,再切换到微信主界面,进入朋友圈,就会自动执行点赞程序了。

效果图如下:

使用AccessibilityService实现自动遍历点赞功能

实现原理步骤以及难点:

1.首先要获取到微信朋友圈这个界面的ListView结点,或者通过根节点描述判断是否进入该界面。

2.到了朋友圈界面之后可以执行程序方法体了,但是要有个boolean值判断只能执行一次。

为什么该方法体只能执行一次呢?(代码在下面有),因为如果被动地让onAccessibilityEvent调用我们的方法,会出现很多问题,比如结点刷新过快,多次触发方法导致点赞步骤同时执行N次然后无限死循环,因为onAccessibilityEvent触发太快了,大概0.几毫秒触发一次,所以我最后让方法体只触发一次,再每秒钟休眠1次确保结点有足够的时间刷新,也保证了执行的稳定性。

3.记录下用户自己的名字,比如我的是“至秦的瓜”,然后我在下面每个item的结点里去找到点赞区域,然后找是否有“至秦的瓜”这个字段,有的话说明这条朋友圈已经赞过了,跳过去,没有则执行点赞。

4.点赞程序的执行,则没什么难度了,代码都看得懂,这里就一带而过了。 

代码实现:


/**
* Created by jiangzn on 17/2/6.
*/
public class MyAccessibilityService extends AccessibilityService {

@Override
 protected void onServiceConnected() {
   LogUtils.d("onServiceConnected");
 }

String description;

ArrayList<Integer> topList = new ArrayList<>();

List<AccessibilityNodeInfo> lvs;

@Override
 public void onAccessibilityEvent(AccessibilityEvent event) {
   try {

//微信UI界面的根节点,开始遍历节点
     AccessibilityNodeInfo rootNodeInfo = getRootInActiveWindow();
     if (rootNodeInfo == null) {
       return;
     }
     description = "";
     if (rootNodeInfo.getContentDescription() != null) {
       description = rootNodeInfo.getContentDescription().toString();
     }

//自动点赞流程
     if (mUserName.equals("")) {
       //Lv
       lvs = rootNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cn0");
       LogUtils.d("找到的Lv数量: " + lvs.size());
       //如果size不为0,证明当前在朋友圈页面下,开始执行逻辑
       if (lvs.size() != 0) {
         //1.先记录用户名
         List<AccessibilityNodeInfo> userNames =
             rootNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/afa");
         if (userNames.size() != 0) {
           if (userNames.get(0).getParent() != null && userNames.get(0).getParent().getChildCount() == 4) {
             mUserName = userNames.get(0).getText().toString();
             if (!mUserName.equals("") && !ifOnce) {
               LogUtils.d("初始化,只会执行一次");
               LogUtils.d("当前的用户名:" + mUserName);
               ifOnce = true;
               //测试朋友圈点赞
               test3(rootNodeInfo);
             }
           }
         }
       } else {
         ifOnce = false;
         mUserName = "";
       }

}

} catch (Exception e) {
     if (e != null && e.getMessage() != null) {
       LogUtils.d("报错:" + e.getMessage().toString());
     }
   }

}

String mUserName = "";
 private boolean ifOnce = false;

/**
  * com.tencent.mm:id/cn0
  * 朋友圈点赞 (目前实现手动滚动全部点赞)
  * 上方固定显示的名字:com.tencent.mm:id/afa
  * 下方点赞:显示id:com.tencent.mm:id/cnn
  * 每发现一个【评论按钮】,就去搜索当前同父组件下的点赞区域有没有自己的ID。
  * 如果有就不点赞,如果没有就点赞
  * 这里要改成不通过Id抓取提高稳定性
  *
  * @param rootNodeInfo
  */
 private synchronized void test3(AccessibilityNodeInfo rootNodeInfo) {
   LogUtils.d("当前线程:" + Thread.currentThread());
   try {
     Thread.sleep(1000);
   } catch (InterruptedException e) {
     e.printStackTrace();
   }

topList.clear();

if (!mUserName.equals("")) {

//测试获得评论按钮的父节点,再反推出点赞按钮
     List<AccessibilityNodeInfo> fuBtns =
         rootNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/co0");

LogUtils.d("fuBtns数量:" + fuBtns.size());

if (fuBtns.size() != 0) {

//删掉超出屏幕的fuBtn
       AccessibilityNodeInfo lastFuBtn = fuBtns.get(fuBtns.size() - 1);
       Rect lastFuBtnOutBound = new Rect();
       lastFuBtn.getBoundsInScreen(lastFuBtnOutBound);
       if (lastFuBtnOutBound.top > Config.height) {
         fuBtns.remove(lastFuBtn);
       }

for (int i = 0; i < fuBtns.size(); i++) {
         AccessibilityNodeInfo fuBtn = fuBtns.get(i);
         LogUtils.d("fuBtn的子节点数量:" + fuBtn.getChildCount());//3-4个
         List<AccessibilityNodeInfo> plBtns = fuBtn.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cj9");
         LogUtils.d("从这里发现评论按钮:" + plBtns.size());

if (plBtns.size() == 0) {
           if (lvs.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
             test3(getRootInActiveWindow());
           }
           return;
         }

AccessibilityNodeInfo plbtn = plBtns.get(0);  //评论按钮
         List<AccessibilityNodeInfo> zanBtns = fuBtn.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cnn");
         LogUtils.d("从这里发现点赞文字显示区域:" + zanBtns.size());
         if (zanBtns.size() != 0) {
           //2.如果不为空,则查找有没有自己点过赞,有则不点,没有则点
           AccessibilityNodeInfo zanbtn = zanBtns.get(0);
           LogUtils.d("点赞的人是:" + zanbtn.getText().toString());
           if (zanbtn != null && zanbtn.getText() != null &&
               zanbtn.getText().toString().contains(mUserName)) {
             LogUtils.d("*********************这一条已经被赞过辣");
             //判断是否需要翻页,如果当前所有页面的父节点都没点过了,就需要翻页
             boolean ifxuyaofanye = false;
             LogUtils.d("O(≧口≦)O: i=" + i + " fuBtns.size():" + fuBtns.size());
             if (i == fuBtns.size() - 1) {
               ifxuyaofanye = true;
             }
             if (ifxuyaofanye) {
               //滑动前检测一下是否还有没有点过的点
               if (jianceIfLou()) {
                 LogUtils.d("还有遗漏的点!!!!再检查一遍!!!!!!!!!!");
                 test3(getRootInActiveWindow());
               } else {
                 if (lvs.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
                   test3(getRootInActiveWindow());
                   return;
                 }
               }
             }

} else {
             LogUtils.d("**************************:自己没有赞过!");
             //开始执行点赞流程
             if (plBtns.size() != 0) {
               Rect outBounds = new Rect();
               plbtn.getBoundsInScreen(outBounds);
               int top = outBounds.top;

//根据top判断如果已经点开了就不重复点开了
               if (topList.contains(top)) {
                 return;
               }
               //com.tencent.mm:id/cj5 赞
               if (plbtn.performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
                 List<AccessibilityNodeInfo> zanlBtns = rootNodeInfo.
                     findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cj3");
                 if (zanlBtns.size() != 0) {
                   if (!topList.contains(top) && zanlBtns.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
                     topList.add(top);
                     LogUtils.d("topList:" + topList.toString());

//判断是否需要翻页,如果当前所有页面的父节点都没点过了,就需要翻页
                     boolean ifxuyaofanye = false;
                     LogUtils.d("O(≧口≦)O: i=" + i + " fuBtns.size():" + fuBtns.size());
                     if (i == fuBtns.size() - 1) {
                       ifxuyaofanye = true;
                     }
                     if (ifxuyaofanye) {
                       //滑动前检测一下是否还有没有点过的点
                       if (jianceIfLou()) {
                         LogUtils.d("还有遗漏的点!!!!再检查一遍!!!!!!!!!!");
                         test3(getRootInActiveWindow());
                       } else {
                         if (lvs.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
                           test3(getRootInActiveWindow());
                           return;
                         }
                       }

}

}
                 }
               }
             }
           }

} else {
           LogUtils.d("**************************:点赞区域为空!plBtns.size() :" + plBtns.size());

//开始执行点赞流程
           if (plBtns.size() != 0) {

Rect outBounds = new Rect();
             plbtn.getBoundsInScreen(outBounds);
             int top = outBounds.top;

//根据top判断如果已经点开了就不重复点开了
             if (topList.contains(top)) {
               return;
             }
             //com.tencent.mm:id/cj5 赞
             if (plbtn.performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
               List<AccessibilityNodeInfo> zanlBtns = rootNodeInfo.
                   findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cj3");
               if (zanlBtns.size() != 0) {
                 if (!topList.contains(top) && zanlBtns.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
                   topList.add(top);
                   LogUtils.d("topList:" + topList.toString());

//判断是否需要翻页,如果当前所有页面的父节点都没点过了,就需要翻页
                   boolean ifxuyaofanye = false;
                   LogUtils.d("O(≧口≦)O: i=" + i + " fuBtns.size():" + fuBtns.size());
                   if (i == fuBtns.size() - 1) {
                     ifxuyaofanye = true;
                   }
                   if (ifxuyaofanye) {
                     //滑动前检测一下是否还有没有点过的点
                     if (jianceIfLou()) {
                       LogUtils.d("还有遗漏的点!!!!再检查一遍!!!!!!!!!!");
                       test3(getRootInActiveWindow());
                     } else {
                       if (lvs.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
                         test3(getRootInActiveWindow());
                         return;
                       }
                     }
                   }
                 }
               }
             }
           }
         }
       }
     }

}
 }

private boolean jianceIfLou() {
   boolean result = false;
   List<AccessibilityNodeInfo> fuBtns =
       getRootInActiveWindow().findAccessibilityNodeInfosByViewId("com.tencent.mm:id/co0");
   LogUtils.d("检查的父节点数量:" + fuBtns.size());
   if (fuBtns.size() != 0) {
     for (AccessibilityNodeInfo fuBtn : fuBtns) {
       //点赞区域
       List<AccessibilityNodeInfo> zanBtns = fuBtn.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cnn");
       LogUtils.d("检查的父节点的点赞区域数量:" + zanBtns.size());
       if (zanBtns.size() != 0) {
         AccessibilityNodeInfo zanbtn = zanBtns.get(0);
         LogUtils.d(" zanbtn.getText().toString():" + zanbtn.getText().toString());
         if (zanbtn != null && zanbtn.getText() != null &&
             zanbtn.getText().toString().contains(mUserName)) {
           result = false;
         } else {
           result = true;
         }
       } else {
         result = true;
       }
     }
   }

return result;
 }

@Override
 public void onInterrupt() {
   LogUtils.d("onInterrupt");
 }

}

辅助服务类的配置方法可以参考上文AccessibilityService——实现微信切换账号功能。

目前的代码有两段几乎重复的,这里没有抽离出来了因为之后我还要进一步优化(恩这就是个demo版不想改了。。)

来源:https://blog.csdn.net/qq_22770457/article/details/55688322

标签:AccessibilityService,点赞
0
投稿

猜你喜欢

  • HashMap 和 Hashtable的区别

    2022-11-01 06:34:47
  • 详解maven中央仓库连不上的解决办法

    2023-02-25 08:43:54
  • springboot+mybatis+枚举处理器的实现

    2023-11-06 00:48:04
  • Android自定义UI手势密码终结版

    2021-07-29 15:40:17
  • Eclipse配置Tomcat和JDK步骤图解

    2022-11-23 11:46:54
  • Android apk 插件启动内存释放问题

    2022-05-16 07:26:39
  • C# DateTime与时间戳转换实例

    2022-12-12 08:34:12
  • Java 深入探究讲解简单工厂模式

    2022-12-25 12:02:06
  • C#实现根据年份计算生肖属相的方法

    2023-04-01 01:12:06
  • 浅谈Java继承中的转型及其内存分配

    2023-11-03 22:56:04
  • C# 生成随机数的代码

    2021-06-16 06:05:43
  • java8 Stream list to Map key 重复 value合并到Collectio的操作

    2022-02-01 23:53:58
  • Unity实现ScrollView滑动吸附功能

    2022-07-07 00:38:14
  • SpringBoot四种读取properties文件的方式(小结)

    2023-10-10 03:25:14
  • C#创建Excel多级分组的方法

    2022-03-21 15:20:34
  • Android开发笔记之Android中数据的存储方式(二)

    2022-12-04 01:05:55
  • Java设计模式之桥接模式的实现

    2021-10-18 20:29:04
  • Hibernate三种状态和Session常用的方法

    2021-11-28 15:04:43
  • 浅谈Java之终止继承:Final类和Fianl方法

    2023-02-14 00:07:08
  • C#控制台下测试多线程的方法

    2022-02-19 15:43:51
  • asp之家 软件编程 m.aspxhome.com