Android微信自动回复功能

article/2025/10/11 17:37:01

Android微信自动回复功能

本文原创,转载请经过本人准许。

写在前面:

最近接到老大的一个需求,要求在手机端拦截微信的通知(Notification),从而获得联系人和内容。之后将联系人和内容发送到我们的硬件产品上,展示出来之后,再将我们想回复内容传给微信,并且发送给相应联系人。

老大还提示我需要用AccessibilityService去实现它,当然在此之前我并不知道AccessibilityService是什么鬼,不过没关系, just do IT

AccessibilityService

AccessibilityService官方文档(需翻墙)

上面这个链接是AccessibilityService的官方文档,可以翻墙点进去了解下,我再给大家总结一下:

AccessibilityService是Android系统框架提供给安装在设备上应用的一个可选的导航反馈特性。AccessibilityService 可以替代应用与用户交流反馈,比如将文本转化为语音提示,或是用户的手指悬停在屏幕上一个较重要的区域时的触摸反馈等。

如果感觉上面的描述比较抽象,没关系,也许你见过下面这张图:

辅助功能中的服务

打开你手机的设置–辅助功能中,有很多APP提供的服务,他们都是基于AccessibilityService编写的,AccessibilityService可以侦听你的点击,长按,手势,通知栏的变化等。并且你可以通过很多种方式找到窗体中的EditText,Button等组件,去填充他们,去点击他们来帮你实现自动化的功能。

像360助手的自动安装功能,它就是侦听着系统安装的APP,然后找到“安装”按钮,实现了自动点击。微信自动抢红包功能,实现方式都是如此。

配置AccessibilityService

首先我们在res文件夹下创建xml文件夹,然后创建一个名为auto_reply_service_config的文件,一会我们会在清单文件中引用它。

AccessibilityService配置文件

代码:

<accessibility-service            xmlns:android="http://schemas.android.com/apk/res/android"     android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged"android:accessibilityFeedbackType="feedbackGeneric"android:accessibilityFlags="flagDefault"android:canRetrieveWindowContent="true"android:description="@string/accessibility_description"android:notificationTimeout="100"android:packageNames="com.tencent.mm" />

这个文件表示我们对AccessibilityService服务未来侦听的行为做了一些配置,比如 typeNotificationStateChangedtypeWindowStateChanged 表示我们需要侦听通知栏的状态变化和窗体状态改变。
android:packageNames=”com.tencent.mm” 这是微信的包名,表示我们只关心微信这一个应用。

代码不打算带着大家一行一行看了,如果有不明白的,去看看文档,或者下面回复我,我给大家解答~

创建AccessibilityService

下面贴出AccessibilityService类的全部代码,注释还算详尽,如有疑问,下方回复。

package com.ileja.autoreply;import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;import java.io.IOException;
import java.util.List;public class AutoReplyService extends AccessibilityService {private final static String MM_PNAME = "com.tencent.mm";boolean hasAction = false;boolean locked = false;boolean background = false;private String name;private String scontent;AccessibilityNodeInfo itemNodeinfo;private KeyguardManager.KeyguardLock kl;private Handler handler = new Handler();/*** 必须重写的方法,响应各种事件。* @param event*/@Overridepublic void onAccessibilityEvent(final AccessibilityEvent event) {int eventType = event.getEventType();android.util.Log.d("maptrix", "get event = " + eventType);switch (eventType) {case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知栏事件android.util.Log.d("maptrix", "get notification event");List<CharSequence> texts = event.getText();if (!texts.isEmpty()) {for (CharSequence text : texts) {String content = text.toString();if (!TextUtils.isEmpty(content)) {if (isScreenLocked()) {locked = true;wakeAndUnlock();android.util.Log.d("maptrix", "the screen is locked");if (isAppForeground(MM_PNAME)) {background = false;android.util.Log.d("maptrix", "is mm in foreground");sendNotifacationReply(event);handler.postDelayed(new Runnable() {@Overridepublic void run() {sendNotifacationReply(event);if (fill()) {send();}}}, 1000);} else {background = true;android.util.Log.d("maptrix", "is mm in background");sendNotifacationReply(event);}} else {locked = false;android.util.Log.d("maptrix", "the screen is unlocked");// 监听到微信红包的notification,打开通知if (isAppForeground(MM_PNAME)) {background = false;android.util.Log.d("maptrix", "is mm in foreground");sendNotifacationReply(event);handler.postDelayed(new Runnable() {@Overridepublic void run() {if (fill()) {send();}}}, 1000);} else {background = true;android.util.Log.d("maptrix", "is mm in background");sendNotifacationReply(event);}}}}}break;case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:android.util.Log.d("maptrix", "get type window down event");if (!hasAction) break;itemNodeinfo = null;String className = event.getClassName().toString();if (className.equals("com.tencent.mm.ui.LauncherUI")) {if (fill()) {send();}else {if(itemNodeinfo != null){itemNodeinfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);handler.postDelayed(new Runnable() {@Overridepublic void run() {if (fill()) {send();}back2Home();release();hasAction = false;}}, 1000);break;}}}//bring2Front();back2Home();release();hasAction = false;break;}}/*** 寻找窗体中的“发送”按钮,并且点击。*/@SuppressLint("NewApi")private void send() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if (nodeInfo != null) {List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("发送");if (list != null && list.size() > 0) {for (AccessibilityNodeInfo n : list) {n.performAction(AccessibilityNodeInfo.ACTION_CLICK);}} else {List<AccessibilityNodeInfo> liste = nodeInfo.findAccessibilityNodeInfosByText("Send");if (liste != null && liste.size() > 0) {for (AccessibilityNodeInfo n : liste) {n.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}}pressBackButton();}}/*** 模拟back按键*/private void pressBackButton(){Runtime runtime = Runtime.getRuntime();try {runtime.exec("input keyevent " + KeyEvent.KEYCODE_BACK);} catch (IOException e) {e.printStackTrace();}}/**** @param event*/private void sendNotifacationReply(AccessibilityEvent event) {hasAction = true;if (event.getParcelableData() != null&& event.getParcelableData() instanceof Notification) {Notification notification = (Notification) event.getParcelableData();String content = notification.tickerText.toString();String[] cc = content.split(":");name = cc[0].trim();scontent = cc[1].trim();android.util.Log.i("maptrix", "sender name =" + name);android.util.Log.i("maptrix", "sender content =" + scontent);PendingIntent pendingIntent = notification.contentIntent;try {pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}}}@SuppressLint("NewApi")private boolean fill() {AccessibilityNodeInfo rootNode = getRootInActiveWindow();if (rootNode != null) {return findEditText(rootNode, "正在忙,稍后回复你");}return false;}private boolean findEditText(AccessibilityNodeInfo rootNode, String content) {int count = rootNode.getChildCount();android.util.Log.d("maptrix", "root class=" + rootNode.getClassName() + ","+ rootNode.getText()+","+count);for (int i = 0; i < count; i++) {AccessibilityNodeInfo nodeInfo = rootNode.getChild(i);if (nodeInfo == null) {android.util.Log.d("maptrix", "nodeinfo = null");continue;}android.util.Log.d("maptrix", "class=" + nodeInfo.getClassName());android.util.Log.e("maptrix", "ds=" + nodeInfo.getContentDescription());if(nodeInfo.getContentDescription() != null){int nindex = nodeInfo.getContentDescription().toString().indexOf(name);int cindex = nodeInfo.getContentDescription().toString().indexOf(scontent);android.util.Log.e("maptrix", "nindex=" + nindex + " cindex=" +cindex);if(nindex != -1){itemNodeinfo = nodeInfo;android.util.Log.i("maptrix", "find node info");}}if ("android.widget.EditText".equals(nodeInfo.getClassName())) {android.util.Log.i("maptrix", "==================");Bundle arguments = new Bundle();arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,true);nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,arguments);nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);ClipData clip = ClipData.newPlainText("label", content);ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);clipboardManager.setPrimaryClip(clip);nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);return true;}if (findEditText(nodeInfo, content)) {return true;}}return false;}@Overridepublic void onInterrupt() {}/*** 判断指定的应用是否在前台运行** @param packageName* @return*/private boolean isAppForeground(String packageName) {ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);ComponentName cn = am.getRunningTasks(1).get(0).topActivity;String currentPackageName = cn.getPackageName();if (!TextUtils.isEmpty(currentPackageName) && currentPackageName.equals(packageName)) {return true;}return false;}/*** 将当前应用运行到前台*/private void bring2Front() {ActivityManager activtyManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningTaskInfo> runningTaskInfos = activtyManager.getRunningTasks(3);for (ActivityManager.RunningTaskInfo runningTaskInfo : runningTaskInfos) {if (this.getPackageName().equals(runningTaskInfo.topActivity.getPackageName())) {activtyManager.moveTaskToFront(runningTaskInfo.id, ActivityManager.MOVE_TASK_WITH_HOME);return;}}}/*** 回到系统桌面*/private void back2Home() {Intent home = new Intent(Intent.ACTION_MAIN);home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);home.addCategory(Intent.CATEGORY_HOME);startActivity(home);}/*** 系统是否在锁屏状态** @return*/private boolean isScreenLocked() {KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);return keyguardManager.inKeyguardRestrictedInputMode();}private void wakeAndUnlock() {//获取电源管理器对象PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);//获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的TagPowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");//点亮屏幕wl.acquire(1000);//得到键盘锁管理器对象KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);kl = km.newKeyguardLock("unLock");//解锁kl.disableKeyguard();}private void release() {if (locked && kl != null) {android.util.Log.d("maptrix", "release the lock");//得到键盘锁管理器对象kl.reenableKeyguard();locked = false;}}
}

接着配置清单文件,权限和service的配置比较重要。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.ileja.autoreply"><uses-permission android:name="android.permission.DISABLE_KEYGUARD" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /><uses-permission android:name="android.permission.GET_TASKS" /><uses-permission android:name="android.permission.REORDER_TASKS" /><uses-permission android:name="android.permission.WAKE_LOCK" /><application
        android: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><service
            android:name=".AutoReplyService"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-data
                android:name="android.accessibilityservice"android:resource="@xml/auto_reply_service_config"/></service></application>
</manifest>

为了使用某些必要的API,最低API level应该是18

运行程序,打开服务,看看效果如何把~

打开辅助服务

接着用其他手机试着发送给我几条微信

自动回复微信

可以看到,自动回复功能就实现了。

写在后面:

代码没有给大家详细讲解,不过看注释应该可以看懂个大概。当微信程序切换到后台,或者锁屏(无锁屏密码)时,只要有通知出现,都可以实现自动回复。

关于AccessibilityService可以监控的行为非常多,所以我觉得可以实现各种各样炫酷的功能,不过我并不建议你打开某些流氓软件的AccessibilityService服务,因为很有可能造成一些安全问题,所以,自己动手写就安全多了嘛。


http://chatgpt.dhexx.cn/article/e7L9fFfN.shtml

相关文章

微信小程序自动回复用户消息

最近用java做了一个实现在微信小程序内根据用户发送的消息内容回复用不通的消息功能&#xff0c;相当于一个自动回复的客服消息,效果图如下&#xff1a; 当用户在小程序输入框中输入内容或其他操作时&#xff0c;后台根据用户输入的内容动态给用户回复&#xff0c;微信的参考文…

微信群怎么自动回复消息?微信群有关键字自动回复功能吗?

在社群运营中&#xff0c;需要经历创建群、拉新&#xff0c;引流&#xff0c;活跃&#xff0c;留存&#xff0c;转化等一系列的过程&#xff0c;而且社群数量和规模会逐渐增加与扩大&#xff0c;这是社群变现必经之路。对于运营者来说&#xff0c;却是一件费时费力的事情。 在…

微信自动回复小程序(有手就行)

昨天刷B站看见了个微信自动回复小程序视频作者是不高兴就喝水视频在这看着感觉挺有意思的我也搞个敷衍我女朋友。 安装python3.4以上版本&#xff0c;并配置环境变量&#xff01;&#xff01;&#xff01; 1.安装依赖包 方法&#xff1a;在cmd中&#xff08;winR 输入cmd …

企业微信可以自动回复吗?

为节省群内成员时间&#xff0c;提升工作效率&#xff0c;快速响应客户问题&#xff0c;企业微信支持配置自动回复&#xff0c;本文介绍如何设置企业微信自动回复和群聊机器人。 企业微信如何设置自动回复&#xff1f; 自动回复&#xff1a;是针对客户的常见问题而设置的标准回…

微信自动回复怎么设置呢?

友友们 你们是否有以下这些烦恼 1、每天要手动点击“添加”按钮多次以通过大量好友? 2、你是否经常需要在多个微信帐号之间来回切换&#xff1f; 3、你的回复速度慢&#xff0c;导致客户流失率高&#xff1f; 4、为了及时回复&#xff0c;你总是需要带着多部手机出门&…

java 输入学习

java输入学习 ①输入需要用到的类Scanner②声明对象③用户输入值给变量④char类型的输入⑤拓展 ①输入需要用到的类Scanner 在开头打出import java.util.Scanner; 以便调用输入 ②声明对象 Scanner input new Scanner(System.in); 声明 输入对象 input 也可以用去它的名字 …

java 输入函数_java新手问题——输入函数

展开全部 可以利用32313133353236313431303231363533e59b9ee7ad9431333366306532Scanner类实现从键盘读入数据&#xff0c;然后利用println打印。 输入以下代码&#xff1a; import java.util.*; public class woo { public static void main(String args[]) { Scanner innew S…

java 输入一个数,判断是奇数还是偶数

java 输入一个数&#xff0c;判断是奇数还是偶数 package shixun1;import java.util.Scanner;public class Shixun1 {public static void main(String[] args) {// 输入一个数&#xff0c;判断是奇数还是偶数Scanner input new Scanner(System.in);System.out.println("…

在java中如何输入_java如何输入

❶ java 如何从键盘上接受输入 public class import { public static void main(String[] args) { System.out.println("请输入一个整数:"); //文字提示 Scanner scan new Scanner(System.in); //用Scanner类定义一个输入对版象 int mscan.nextInt(); //输入对象赋值…

Java 输入年份、月份,输出当月日历表

总体的逻辑思路&#xff1a; 1、以1900年1月1号&#xff08;星期一&#xff09;为初始日期用来计算截止到输入年份的上一年最后一天的总天数&#xff1b; 2、计算截止到输入月份的上一个月最后一天的总天数进行 3、将获得的总天数%7得到剩余i天&#xff0c;则i1天则为当月1号…

Java 输入三个整数 从小到大排列

今天突然一想控制台输入三个数&#xff0c;如何将这三个数从小到大排序 经过短暂的思考&#xff0c;直接上代码&#xff1a; public class Test04 {public static void main(String[] args) {demo01();} /*7.题目&#xff1a;输入三个整数x,y,z&#xff0c;请把这三个数由小到…

java 输入正整数_JAVA输入一个正整数n, 再输入n个整数,输出最大值。

展开全部 import java.util.Scanner; public class Test { public static void main(String[] args){ int repeat 0,n; int max 0; Scanner innew Scanner(System.in); maxin.nextInt(); System.out.println("请输入您要比较的整数的个62616964757a686964616fe4b893e5b1…

数字倒序Java_java输入数字,输出倒序的实例

java输入数字,输出倒序的实例,逆序,整数,给大家,请输入,三种 java输入数字,输出倒序的实例 易采站长站&#xff0c;站长之家为您整理了java输入数字,输出倒序的实例的相关内容。 我就废话不多说了&#xff0c;大家还是直接看代码吧~ package c10; import java.util.Scanner; pu…

java输入非整数异常处理

在java程序中&#xff0c;我们经常会遇到从键盘输入接收数据问题&#xff0c;但是有时会碰到输入数据类型与所需数据类型不一致的问题&#xff0c;这时就很可能导致程序报错直接退出&#xff0c;因此&#xff0c;这时用异常处理就显得格外重要&#xff0c;下面来介绍一个简单的…

Java中输入的用法

Java中输入 1、 读取输入 1&#xff09;构建一个Scanner&#xff0c;附属到System.in Scanner in new Scanner(System.in); 此时可以使用Scanner类的各种方法来读取输入。例如&#xff1a;nextLine方法来读取一行输入 System.out.print("What is your name?"); Str…

大事件,Java被超越了,2021年5月TIOBE编程语言排行榜出炉

TIOBE 头条 TIOBE 5月编程语言排行榜新鲜出炉。前十榜单中&#xff0c;C、Python、Java三大鳌头仍占据前三榜单。去年11月&#xff0c;Python短时间的挤掉Java跃居至榜单第二名&#xff1b;今年5月&#xff0c;Python再次挤掉Java&#xff0c;再度夺下榜二。 TIOBE排行榜是世…

TIOBE 7 月编程语言排行榜:C、Java 和 Python 争夺第一

整理 | 郑丽媛 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; TIOBE 官方最新发布了 7 月的编程语言榜单&#xff0c;而本月也是 TIOBE 榜单成立 20 周年&#xff0c;一起来看这个月榜单中有哪些最新变化吧&#xff1f; C、Java 和 Python 争夺第一 回想 2001 年…

编程语言排行榜迎来历史性时刻!C语言和Java均败了!

持续更新 20 多年的Tiobe编程语言排行榜&#xff0c;迎来了一个历史性时刻&#xff01;第一次拥有一个新的领导者&#xff1a;Python 编程语言。 这就意味着 Java 和 C 的长期霸权已经结束。Python 作为一种简单的脚本语言开始作为 Perl 的替代品&#xff0c;现在已经成熟。它…

2022年12月编程语言排行榜,数据来了!

2022年迎来了最后一个月&#xff0c;我们可以看到&#xff0c;在这一年中编程语言起起伏伏&#xff0c;有的语言始终炙手可热&#xff0c;而有的语言却逐渐“没落”...... 日前&#xff0c;全球知名TIOBE编程语言社区发布了12月编程语言排行榜&#xff0c;有哪些新变化&#xf…

2021年2月中国编程语言排行榜来了!

编程语言比例(市场份额) 工资 rankpl_平均工资工资中位数最低工资(2.5%)最高工资(97.5%)招聘人数百分比1haskell2516722500200003300030.0%2rust20732185005000450005150.1%3julia19194200001150027500420.0%4scala191091750052505715432840.7%5matlab18606175005134450007007…