AccessibilityService

AccessibilityService官方文档(需)

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

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

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

Android通过AccessibilityService实现微信自动回复功能_第1张图片
辅助功能中的服务

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

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

配置AccessibilityService

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

Android通过AccessibilityService实现微信自动回复功能_第2张图片
AccessibilityService配置文件

代码:

这个文件表示我们对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     */    @Override    public 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 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() {                                        @Override                                        public 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() {                                        @Override                                        public 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() {                                @Override                                public 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 list = nodeInfo                    .findAccessibilityNodeInfosByText("发送");            if (list != null && list.size() > 0) {                for (AccessibilityNodeInfo n : list) {                    n.performAction(AccessibilityNodeInfo.ACTION_CLICK);                }            } else {                List 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;    }    @Override    public 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 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对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag        PowerManager.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"?>                                                                                                                                                                                    

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

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

Android通过AccessibilityService实现微信自动回复功能_第3张图片
打开辅助服务

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

Android通过AccessibilityService实现微信自动回复功能_第4张图片
自动回复微信

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

写在后面:

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

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

github项目地址:
WcAutoReply


原文链接:http://www.jianshu.com/p/f67e950d84f7

更多相关文章

  1. listView背景问题以及限制editText字数以及如果想通知别人已经不
  2. Android系统移植与调试之------->如何修改Android设备添加重启、
  3. 用HTML+JS实现Android闹钟功能,附带Alarm代码分享
  4. Android各版本新增功能一览
  5. Android ListAdapter的高级功能
  6. 给App启用MultiDex功能
  7. android studio如何合并和读取多个相同功能但是文本不同的按钮
  8. Android实现发送短信验证码倒计时功能

随机推荐

  1. Android缓存浅析
  2. Android系列教程之六:TextView小组件的使
  3. Android ImageView 的scaleType 属性图解
  4. Android控件之利用selector自定义的带文
  5. Android WebView实现离线加载功能
  6. 使用Vitamio打造自己的Android万能播放器
  7. Android手势ImageView之(自定义GestureDet
  8. Android事件总线之EventBus3.0基本使用
  9. 给大家介绍几个常见的Android代码片段
  10. 很好的一些开源项目(转自:http://www.uur