前言

最近在研究Android辅助服务,实现了这个小工具,也算是对最近学习的一个总结。

原理

通过Android 无障碍辅助功能实现模拟点击控件来实现
检查被删好友有两种方法:

  1. 向好友发送一条消息,如果对方已经把你删除,则消息发送失败。
  2. 建群法:新建一个不大于40人的群,如果其中有好友已经把你删除,微信会有条消息提示
  3. 整体执行步骤:启动微信->点击+号->发起群聊->选择35个联系人->点击确定->点击群里详情->删除并退出,依次轮询执行,知道所有好友轮询结束。

本文采用建群的方式进行检查。
本人微信有300好友,全部检测一遍只需3分钟即可,亲测已经成功,
但是建群没有超过40人 会有个别好友会受到打扰消息,可能是微信哪里的bug,具体原因未知。

说明和app预览

此软件通过无障碍辅助进行模拟点击,无任何外挂木马,无封号风险

使用方法

  1. Android 手机一部,登录微信账号
  2. 安装辅助软件apk下载地址请点击这里
  3. 打开辅助软件-点击打开辅助功能按钮,跳转到无障碍辅助设置把辅助开关打开。
  4. 点击开始检查按钮,开始一系列的模拟点击,检查完成后会跳转到一个列表会把被删好友列表展示出来。

实现步骤:

  • 新建Android Studio 工程,新建一个Services类集成AccessibilityService,实现对应方法,详细介绍见代码注释

/*** Created by wanglj on 16/10/20.*/public class InspectWechatFriendService extends AccessibilityService{@Overrideprotected void onServiceConnected() {//辅助服务被打开后 执行此方法super.onServiceConnected();}@Overridepublic void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {//监听手机当前窗口状态改变 比如 Activity 跳转,内容变化,按钮点击等事件}@Overridepublic void onInterrupt() {//辅助服务被关闭 执行此方法}
}
  • 在manifests.xml文件中注册此服务:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.wanglj.inspectwechatfriend"xmlns:android="http://schemas.android.com/apk/res/android"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><serviceandroid:name=".accessibility.InspectWechatFriendService"android:enabled="true"android:exported="true"android:label="@string/app_name"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService"/></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/inspect_wechat_friend"/></service></application></manifest>
  • 新建res/xml/inspect_wechat_friend.xml文件
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric"android:accessibilityFlags=""android:canRetrieveWindowContent="true"android:notificationTimeout="100"android:description="@string/accessibility"/>
  • 实现对某个控件的点击

通过getRootInActiveWindow方法获取当前窗口信息,通过findAccessibilityNodeInfosByText方法找到当前对应控件进行模拟点击


public class PerformClickUtils {/*** 在当前页面查找文字内容并点击** @param text*/public static void findTextAndClick(AccessibilityService accessibilityService,String text) {AccessibilityNodeInfo accessibilityNodeInfo = accessibilityService.getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);if (nodeInfoList != null && !nodeInfoList.isEmpty()) {for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {if (nodeInfo != null && (text.equals(nodeInfo.getText()) || text.equals(nodeInfo.getContentDescription()))) {performClick(nodeInfo);break;}}}}/*** 检查viewId进行点击* * @param accessibilityService* @param id*/public static void findViewIdAndClick(AccessibilityService accessibilityService,String id) {AccessibilityNodeInfo accessibilityNodeInfo = accessibilityService.getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);if (nodeInfoList != null && !nodeInfoList.isEmpty()) {for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {if (nodeInfo != null) {performClick(nodeInfo);break;}}}}/*** 在当前页面查找对话框文字内容并点击** @param text1 默认点击text1* @param text2*/public static void findDialogAndClick(AccessibilityService accessibilityService,String text1, String text2) {AccessibilityNodeInfo accessibilityNodeInfo = accessibilityService.getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> dialogWait = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text1);List<AccessibilityNodeInfo> dialogConfirm = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text2);if (!dialogWait.isEmpty() && !dialogConfirm.isEmpty()) {for (AccessibilityNodeInfo nodeInfo : dialogWait) {if (nodeInfo != null && text1.equals(nodeInfo.getText())) {performClick(nodeInfo);break;}}}}//模拟点击事件public static void performClick(AccessibilityNodeInfo nodeInfo) {if (nodeInfo == null) {return;}if (nodeInfo.isClickable()) {nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);} else {performClick(nodeInfo.getParent());}} //模拟返回事件public static void performBack(AccessibilityService service) {if (service == null) {return;}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);}}
}
  • 监听窗口事件

获取当前窗口的classname 通过classname进行判断当前手机处于某个界面
下面代码逻辑:

  1. 如果当前为微信主页面,则点击+号然后点击发起群聊
  2. 如果当前页面为创建群聊选择联系人界面,则开启一个while循环模拟滚动时间以及点击选择框,当选择用户到39人时,则模拟点击确定按钮发起群聊。
  3. 发起群聊后,微信会返回哪些用户不是你的好友,这个时候,取到当前控件的字符串并截取用户列表保存到本地。
  4. 获取到不是好友的用户后,点击右上角进入群聊详情,点击删除并退出
  5. 退出后又回到微信主页面,依次执行1 2 3 4步骤,直到滚动到联系人最底部为止。
  6. 当所有用户执行完成后,则启动检查结果界面,列出所有被删好友。

下面为对应逻辑代码:

 @Overridepublic void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {//监听手机当前窗口状态改变 比如 Activity 跳转,内容变化,按钮点击等事件//如果手机当前界面的窗口发送变化if (accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {//获取当前activity的类名:String currentWindowActivity = accessibilityEvent.getClassName().toString();if(!hasComplete){if ("com.tencent.mm.ui.contact.SelectContactUI".equals(currentWindowActivity)) {canChecked = true;createGroup();} else if ("com.tencent.mm.ui.chatting.ChattingUI".equals(currentWindowActivity)) {getDeleteFriend();} else if ("com.tencent.mm.plugin.chatroom.ui.ChatroomInfoUI".equals(currentWindowActivity)) {deleteGroup();}else if("com.tencent.mm.ui.LauncherUI".equals(currentWindowActivity)){PerformClickUtils.findTextAndClick(this,"更多功能按钮");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}PerformClickUtils.findTextAndClick(this,"发起群聊");}}else{nickNameList.clear();deleteList.clear();sortItems.clear();startActivity(new Intent(this, DeleteFriendListActivity.class));}}}/*** 模拟创建群组步骤*/private void createGroup() {AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> listview = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(selectUI_listview_id);int count = 0;if (!listview.isEmpty()) {while (canChecked) {List<AccessibilityNodeInfo> checkboxList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(selectUI_checkbox_id);List<AccessibilityNodeInfo> sortList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(selectUI_sortitem_id);for(AccessibilityNodeInfo nodeInfo:sortList){if(nodeInfo != null && nodeInfo.getText()!= null){sortItems.add(nodeInfo.getText().toString());}}for (AccessibilityNodeInfo nodeInfo : checkboxList) {String nickname = nodeInfo.getParent().findAccessibilityNodeInfosByViewId(selectUI_nickname_id).get(0).getText().toString();Log.e(TAG, "nickname = " + nickname);if (!nickNameList.contains(nickname)) {nickNameList.add(nickname);performClick(nodeInfo);count++;if (count >= GROUP_COUNT || nickNameList.size() >= listview.get(0).getCollectionInfo().getRowCount() - sortItems.size() - 2) {List<AccessibilityNodeInfo> createButtons = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(selectUI_create_button_id);if (!createButtons.isEmpty()) {performClick(createButtons.get(0));}if(nickNameList.size() >= listview.get(0).getCollectionInfo().getRowCount() - sortItems.size() - 2){hasComplete = true;}return;}}}listview.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}/*** 模拟获取被删好友列表步骤*/private void getDeleteFriend() {AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(chattingUI_message_id);for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {if (nodeInfo != null && nodeInfo.getText() != null && nodeInfo.getText().toString().contains("你无法邀请未添加你为好友的用户进去群聊,请先向")) {String str = nodeInfo.getText().toString();str = str.replace("你无法邀请未添加你为好友的用户进去群聊,请先向", "");str = str.replace("发送朋友验证申请。对方通过验证后,才能加入群聊。", "");String[] arr = str.split("、");deleteList.addAll(Arrays.asList(arr));Preferences.saveDeleteFriends(this);Log.e(TAG, "deleteList.size():" + deleteList.size());Toast.makeText(this, "僵尸粉数量:" + deleteList.size(), Toast.LENGTH_SHORT).show();break;}}PerformClickUtils.findTextAndClick(this,"聊天信息");}/*** 退出群组步骤*/private void deleteGroup(){AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();if (accessibilityNodeInfo == null) {return;}List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(groupinfoUI_listview_id);if (!nodeInfoList.isEmpty()) {nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);PerformClickUtils.findTextAndClick(this,"删除并退出");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}PerformClickUtils.findTextAndClick(this,"删除并退出");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
//            if(Utils.getVersion(this).equals(WECHAT_VERSION_27)){
//                PerformClickUtils.findTextAndClick(this,"确定");
//            }else{PerformClickUtils.findTextAndClick(this,"离开群聊");PerformClickUtils.findTextAndClick(this,"确定");
//            }}}

ui automator viewer的使用

uiautomatorviewer可以检查当前手机的布局结构,如果想更精确的找到控件位置,uiautomatorviewer必不可少!

使用方法:

  1. 搭建Android开发环境,并设置环境变量,这里就不说了。
  2. 在Android Studio 中打开 terminal 窗口,或者在终端直接执行命令
$uiautomatorviewer

整体效果图:

竟然可以检查微信是否被删了好友?(Android Accessibility 了解一下)相关推荐

  1. 微信如何恢复删掉的好友,巧妙添加好友的方法汇总

    好友删除了,微信如何恢复删掉的好友?最直接的办法当然是联系上好友,然后再重新加回TA.然而状况往往总是有点复杂,很多时候并不是因为一时手滑把好友删除了.而是和朋友闹了一点小矛盾,一时生气把TA删除了, ...

  2. 你好,我的Dev-C++ 5.15被烦人的360杀毒软件给删了,放到白名单里之后就360竟然把所有的浏览器全部删掉了,请问怎么办

    markdown 你好,我的Dev-C++ 5.15被烦人的360杀毒软件给删了,放到白名单里之后就360竟然把所有的浏览器全部删掉了,请问怎么办 1+2=3 hello, world! 文章目录 m ...

  3. 微信无感知检测单项好友【WeTool 免费版】【微信如何检测单向好友?】

    一.微信无感知检测单项好友 1.1 背景 因为最近业务的原因加了好多的陌生微信好友,难免有很多好友删了我,但是我还有他的微信,岂不是很占地方? 所以我琢磨如何检测这些单项好友[利用转账.拉群的方法太费 ...

  4. 微信APP支付服务端和Android 端详解及其demo

    最近在开发APP微信支付和支付宝支付,Android 端和后端都是我自己开发的,发现两家公司的文档都不是很友好,特别是微信,接触过或者开发过的人都应该有所体会.因此我特意把开发的过程梳理了,做下记录, ...

  5. cocos2dx3.15接入微信SDK实现登录和分享android studio2.3.3

    cocos2dx3.15接入微信SDK实现登录和分享android studio2.3.3,首先开始呢,我必须得吐槽一下网上的教程以及微信开放平台官网,网上的教程主要是太老了代码虽然都能用但是不完整有 ...

  6. 30 | 图的表示:如何存储微博、微信等社交网络中的好友关系?

    列出功能需求->翻译成逻辑算法->抽象出数据结构->确定物理存储结构 后面的不会脱离前面的独立存在,只存在于工作流的运用中,所以不能把它们独立地看. 问题引入 在微博中,两个人可以互 ...

  7. 图的表示:如何存储微博、微信等社交网络中的好友关系

    微博.微信.LinkedIn 这些社交软件我想你肯定都玩过吧.在微博中,两个人可以互相关注:在微信中,两个人可以互加好友.那你知道,如何存储微博.微信等这些社交网络的好友关系吗? 这就要用到我们今天要 ...

  8. python clicknium 微信发送消息以及获取好友列表

    需求说明 给指定微信好友发消息 获取所有微信好友的微信号 环境准备 Windows 10 Visual Studio Code 1.69.2 Clicknium 0.1.2 Python 3.10.5 ...

  9. 【图的表示】:如何存储微博、微信等社交网络中的好友关系?

    微博.微信.LinkedIn 这些社交软件我想你肯定都玩过吧.在微博中,两个人可以互相关注:在微信中,两个人可以互加好友.那你知道,如何存储微博.微信等这些社交网络的好友关系吗? 这就要用到我们今天要 ...

最新文章

  1. 漏洞高危 中危 低危的划分标准
  2. C语言 一个字符常量占几个字节
  3. php万年历月份处理_php实现万年历的完整代码
  4. 第三次学JAVA再学不好就吃翔(part17)--数组
  5. esb 和mq_使用保险丝结构管理MQ和ESB的大型部署,第一部分
  6. 计算机网络应用云计算,计算机网络云计算的类型
  7. python求解多元方程最优解_Python实现梯度下降算法求多元线性回归(二)
  8. DataGridView的单元格内容即时更新方法
  9. SAP License:SAP PM的应用从实施开始
  10. 在java中String类为什么要设计成final
  11. mysql binlog 备份_linux定时备份mysql数据库
  12. 《未来编年史》——关于地球未来2000年的预言
  13. chip_seq数据分析专题
  14. i.MX6ULL驱动开发 | 10 - 修改LCD驱动点亮LCD显示小企鹅logo
  15. 使用python合并多个pdf文件
  16. win10升级助手_Win10自带杀毒软件如此强大,大家却不爱用,究竟是为什么呢?...
  17. 新华三:照耀城市的数字演进之路
  18. 计算机sci检索,计算机方向国内EI检索、SCI检索的期刊目录
  19. 【商业信息】PNP ID注册名单 2019-05-21
  20. 微信指数来了,营销人又有新工具

热门文章

  1. android推送设置功能
  2. 只保留3天!《算法学习》入门到进阶,超全配套案例下载
  3. 阿里张建锋:互联网主要解决三大问题
  4. 乐视手机恢复出厂设置后卡账户登录页面,刷入miui系统后妥妥的开发手机
  5. 如何一次性查询千百个顺丰快递的详细物流信息
  6. 科技巨头争相布局物联网 智能家居成争夺主战场
  7. 前端证券项目_富途证券WEB前端团队招募令
  8. 学习淘宝分享出来的链接web检测打开原生App
  9. JAVA计算机毕业设计员工健康检测系统Mybatis+源码+数据库+lw文档+系统+调试部署
  10. C语言简单五子棋两人/五子棋人机