Android通过AccessibilityService实现微信自动回复功能

AccessibilityService

AccessibilityService官方文档(需翻墙)

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

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

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


辅助功能中的服务

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

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

配置AccessibilityService

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


AccessibilityService配置文件

代码:

  1. <accessibility-service xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     android:accessibilityEventTypes=”typeNotificationStateChanged|typeWindowStateChanged”  
  3.     android:accessibilityFeedbackType=”feedbackGeneric”  
  4.     android:accessibilityFlags=”flagDefault”  
  5.     android:canRetrieveWindowContent=”true”  
  6.     android:description=”@string/accessibility_description”  
  7.     android:notificationTimeout=”100”  
  8.     android:packageNames=”com.tencent.mm” />  
<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类的全部代码,注释还算详尽,如有疑问,下方回复。

  1. package com.ileja.autoreply;  
  2.   
  3. import android.accessibilityservice.AccessibilityService;  
  4. import android.annotation.SuppressLint;  
  5. import android.app.ActivityManager;  
  6. import android.app.KeyguardManager;  
  7. import android.app.Notification;  
  8. import android.app.PendingIntent;  
  9. import android.content.ClipData;  
  10. import android.content.ClipboardManager;  
  11. import android.content.ComponentName;  
  12. import android.content.Context;  
  13. import android.content.Intent;  
  14. import android.os.Bundle;  
  15. import android.os.Handler;  
  16. import android.os.PowerManager;  
  17. import android.text.TextUtils;  
  18. import android.view.KeyEvent;  
  19. import android.view.accessibility.AccessibilityEvent;  
  20. import android.view.accessibility.AccessibilityNodeInfo;  
  21.   
  22. import java.io.IOException;  
  23. import java.util.List;  
  24.   
  25. public class AutoReplyService extends AccessibilityService {  
  26.     private final static String MM_PNAME = “com.tencent.mm”;  
  27.     boolean hasAction = false;  
  28.     boolean locked = false;  
  29.     boolean background = false;  
  30.     private String name;  
  31.     private String scontent;  
  32.     AccessibilityNodeInfo itemNodeinfo;  
  33.     private KeyguardManager.KeyguardLock kl;  
  34.     private Handler handler = new Handler();  
  35.   
  36.   
  37.     /** 
  38.      * 必须重写的方法,响应各种事件。 
  39.      * @param event 
  40.      */  
  41.     @Override  
  42.     public void onAccessibilityEvent(final AccessibilityEvent event) {  
  43.         int eventType = event.getEventType();  
  44.         android.util.Log.d(”maptrix”“get event = ” + eventType);  
  45.         switch (eventType) {  
  46.             case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知栏事件  
  47.                 android.util.Log.d(”maptrix”“get notification event”);  
  48.                 List<CharSequence> texts = event.getText();  
  49.                 if (!texts.isEmpty()) {  
  50.                     for (CharSequence text : texts) {  
  51.                         String content = text.toString();  
  52.                         if (!TextUtils.isEmpty(content)) {  
  53.                             if (isScreenLocked()) {  
  54.                                 locked = true;  
  55.                                 wakeAndUnlock();  
  56.                                 android.util.Log.d(”maptrix”“the screen is locked”);  
  57.                                 if (isAppForeground(MM_PNAME)) {  
  58.                                     background = false;  
  59.                                     android.util.Log.d(”maptrix”“is mm in foreground”);  
  60.                                     sendNotifacationReply(event);  
  61.                                     handler.postDelayed(new Runnable() {  
  62.                                         @Override  
  63.                                         public void run() {  
  64.                                             sendNotifacationReply(event);  
  65.                                             if (fill()) {  
  66.                                                 send();  
  67.                                             }  
  68.                                         }  
  69.                                     }, 1000);  
  70.                                 } else {  
  71.                                     background = true;  
  72.                                     android.util.Log.d(”maptrix”“is mm in background”);  
  73.                                     sendNotifacationReply(event);  
  74.                                 }  
  75.                             } else {  
  76.                                 locked = false;  
  77.                                 android.util.Log.d(”maptrix”“the screen is unlocked”);  
  78.                                 // 监听到微信红包的notification,打开通知  
  79.                                 if (isAppForeground(MM_PNAME)) {  
  80.                                     background = false;  
  81.                                     android.util.Log.d(”maptrix”“is mm in foreground”);  
  82.                                     sendNotifacationReply(event);  
  83.                                     handler.postDelayed(new Runnable() {  
  84.                                         @Override  
  85.                                         public void run() {  
  86.                                             if (fill()) {  
  87.                                                 send();  
  88.                                             }  
  89.                                         }  
  90.                                     }, 1000);  
  91.                                 } else {  
  92.                                     background = true;  
  93.                                     android.util.Log.d(”maptrix”“is mm in background”);  
  94.                                     sendNotifacationReply(event);  
  95.                                 }  
  96.                             }  
  97.                         }  
  98.                     }  
  99.                 }  
  100.                 break;  
  101.             case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:  
  102.                 android.util.Log.d(”maptrix”“get type window down event”);  
  103.                 if (!hasAction) break;  
  104.                 itemNodeinfo = null;  
  105.                 String className = event.getClassName().toString();  
  106.                 if (className.equals(“com.tencent.mm.ui.LauncherUI”)) {  
  107.                     if (fill()) {  
  108.                         send();  
  109.                     }else {  
  110.                         if(itemNodeinfo != null){  
  111.                             itemNodeinfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);  
  112.                             handler.postDelayed(new Runnable() {  
  113.                                 @Override  
  114.                                 public void run() {  
  115.                                     if (fill()) {  
  116.                                         send();  
  117.                                     }  
  118.                                     back2Home();  
  119.                                     release();  
  120.                                     hasAction = false;  
  121.                                 }  
  122.                             }, 1000);  
  123.                             break;  
  124.                         }  
  125.                     }  
  126.                 }  
  127.   
  128.                 //bring2Front();  
  129.                 back2Home();  
  130.                 release();  
  131.                 hasAction = false;  
  132.                 break;  
  133.         }  
  134.     }  
  135.   
  136.     /** 
  137.      * 寻找窗体中的“发送”按钮,并且点击。 
  138.      */  
  139.     @SuppressLint(“NewApi”)  
  140.     private void send() {  
  141.         AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();  
  142.         if (nodeInfo != null) {  
  143.             List<AccessibilityNodeInfo> list = nodeInfo  
  144.                     .findAccessibilityNodeInfosByText(”发送”);  
  145.             if (list != null && list.size() > 0) {  
  146.                 for (AccessibilityNodeInfo n : list) {  
  147.                     n.performAction(AccessibilityNodeInfo.ACTION_CLICK);  
  148.                 }  
  149.   
  150.             } else {  
  151.                 List<AccessibilityNodeInfo> liste = nodeInfo  
  152.                         .findAccessibilityNodeInfosByText(”Send”);  
  153.                 if (liste != null && liste.size() > 0) {  
  154.                     for (AccessibilityNodeInfo n : liste) {  
  155.                         n.performAction(AccessibilityNodeInfo.ACTION_CLICK);  
  156.                     }  
  157.                 }  
  158.             }  
  159.             pressBackButton();  
  160.         }  
  161.   
  162.     }  
  163.   
  164.     /** 
  165.      * 模拟back按键 
  166.      */  
  167.     private void pressBackButton(){  
  168.         Runtime runtime = Runtime.getRuntime();  
  169.         try {  
  170.             runtime.exec(”input keyevent ” + KeyEvent.KEYCODE_BACK);  
  171.         } catch (IOException e) {  
  172.             e.printStackTrace();  
  173.         }  
  174.     }  
  175.   
  176.     /** 
  177.      * 
  178.      * @param event 
  179.      */  
  180.     private void sendNotifacationReply(AccessibilityEvent event) {  
  181.         hasAction = true;  
  182.         if (event.getParcelableData() != null  
  183.                 && event.getParcelableData() instanceof Notification) {  
  184.             Notification notification = (Notification) event  
  185.                     .getParcelableData();  
  186.             String content = notification.tickerText.toString();  
  187.             String[] cc = content.split(”:”);  
  188.             name = cc[0].trim();  
  189.             scontent = cc[1].trim();  
  190.   
  191.             android.util.Log.i(”maptrix”“sender name =” + name);  
  192.             android.util.Log.i(”maptrix”“sender content =” + scontent);  
  193.   
  194.   
  195.             PendingIntent pendingIntent = notification.contentIntent;  
  196.             try {  
  197.                 pendingIntent.send();  
  198.             } catch (PendingIntent.CanceledException e) {  
  199.                 e.printStackTrace();  
  200.             }  
  201.         }  
  202.     }  
  203.   
  204.     @SuppressLint(“NewApi”)  
  205.     private boolean fill() {  
  206.         AccessibilityNodeInfo rootNode = getRootInActiveWindow();  
  207.         if (rootNode != null) {  
  208.             return findEditText(rootNode, “正在忙,稍后回复你”);  
  209.         }  
  210.         return false;  
  211.     }  
  212.   
  213.   
  214.     private boolean findEditText(AccessibilityNodeInfo rootNode, String content) {  
  215.         int count = rootNode.getChildCount();  
  216.   
  217.         android.util.Log.d(”maptrix”“root class=” + rootNode.getClassName() + “,”+ rootNode.getText()+“,”+count);  
  218.         for (int i = 0; i < count; i++) {  
  219.             AccessibilityNodeInfo nodeInfo = rootNode.getChild(i);  
  220.             if (nodeInfo == null) {  
  221.                 android.util.Log.d(”maptrix”“nodeinfo = null”);  
  222.                 continue;  
  223.             }  
  224.   
  225.             android.util.Log.d(”maptrix”“class=” + nodeInfo.getClassName());  
  226.             android.util.Log.e(”maptrix”“ds=” + nodeInfo.getContentDescription());  
  227.             if(nodeInfo.getContentDescription() != null){  
  228.                 int nindex = nodeInfo.getContentDescription().toString().indexOf(name);  
  229.                 int cindex = nodeInfo.getContentDescription().toString().indexOf(scontent);  
  230.                 android.util.Log.e(”maptrix”“nindex=” + nindex + “ cindex=” +cindex);  
  231.                 if(nindex != -1){  
  232.                     itemNodeinfo = nodeInfo;  
  233.                     android.util.Log.i(”maptrix”“find node info”);  
  234.                 }  
  235.             }  
  236.             if (“android.widget.EditText”.equals(nodeInfo.getClassName())) {  
  237.                 android.util.Log.i(”maptrix”“==================”);  
  238.                 Bundle arguments = new Bundle();  
  239.                 arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,  
  240.                         AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);  
  241.                 arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,  
  242.                         true);  
  243.                 nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,  
  244.                         arguments);  
  245.                 nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);  
  246.                 ClipData clip = ClipData.newPlainText(”label”, content);  
  247.                 ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);  
  248.                 clipboardManager.setPrimaryClip(clip);  
  249.                 nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);  
  250.                 return true;  
  251.             }  
  252.   
  253.             if (findEditText(nodeInfo, content)) {  
  254.                 return true;  
  255.             }  
  256.         }  
  257.   
  258.         return false;  
  259.     }  
  260.   
  261.     @Override  
  262.     public void onInterrupt() {  
  263.   
  264.     }  
  265.   
  266.     /** 
  267.      * 判断指定的应用是否在前台运行 
  268.      * 
  269.      * @param packageName 
  270.      * @return 
  271.      */  
  272.     private boolean isAppForeground(String packageName) {  
  273.         ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  
  274.         ComponentName cn = am.getRunningTasks(1).get(0).topActivity;  
  275.         String currentPackageName = cn.getPackageName();  
  276.         if (!TextUtils.isEmpty(currentPackageName) && currentPackageName.equals(packageName)) {  
  277.             return true;  
  278.         }  
  279.   
  280.         return false;  
  281.     }  
  282.   
  283.   
  284.     /** 
  285.      * 将当前应用运行到前台 
  286.      */  
  287.     private void bring2Front() {  
  288.         ActivityManager activtyManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  
  289.         List<ActivityManager.RunningTaskInfo> runningTaskInfos = activtyManager.getRunningTasks(3);  
  290.         for (ActivityManager.RunningTaskInfo runningTaskInfo : runningTaskInfos) {  
  291.             if (this.getPackageName().equals(runningTaskInfo.topActivity.getPackageName())) {  
  292.                 activtyManager.moveTaskToFront(runningTaskInfo.id, ActivityManager.MOVE_TASK_WITH_HOME);  
  293.                 return;  
  294.             }  
  295.         }  
  296.     }  
  297.   
  298.     /** 
  299.      * 回到系统桌面 
  300.      */  
  301.     private void back2Home() {  
  302.         Intent home = new Intent(Intent.ACTION_MAIN);  
  303.   
  304.         home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  305.         home.addCategory(Intent.CATEGORY_HOME);  
  306.   
  307.         startActivity(home);  
  308.     }  
  309.   
  310.   
  311.     /** 
  312.      * 系统是否在锁屏状态 
  313.      * 
  314.      * @return 
  315.      */  
  316.     private boolean isScreenLocked() {  
  317.         KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);  
  318.         return keyguardManager.inKeyguardRestrictedInputMode();  
  319.     }  
  320.   
  321.     private void wakeAndUnlock() {  
  322.         //获取电源管理器对象  
  323.         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);  
  324.   
  325.         //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag  
  326.         PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, ”bright”);  
  327.   
  328.         //点亮屏幕  
  329.         wl.acquire(1000);  
  330.   
  331.         //得到键盘锁管理器对象  
  332.         KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);  
  333.         kl = km.newKeyguardLock(”unLock”);  
  334.   
  335.         //解锁  
  336.         kl.disableKeyguard();  
  337.   
  338.     }  
  339.   
  340.     private void release() {  
  341.   
  342.         if (locked && kl != null) {  
  343.             android.util.Log.d(”maptrix”“release the lock”);  
  344.             //得到键盘锁管理器对象  
  345.             kl.reenableKeyguard();  
  346.             locked = false;  
  347.         }  
  348.     }  
  349. }  
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<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() {
                                        @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<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;
    }

    @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<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对象,后面的参数|表示同时传入两个值,最后的是调试用的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的配置比较重要。

  1. <?xml version=“1.0” encoding=“utf-8”?>  
  2. <manifest xmlns:android=”http://schemas.android.com/apk/res/android”  
  3.     package=“com.ileja.autoreply”>  
  4.   
  5.     <uses-permission android:name=”android.permission.DISABLE_KEYGUARD” />  
  6.     <uses-permission android:name=”android.permission.INTERNET” />  
  7.     <uses-permission android:name=”android.permission.MODIFY_AUDIO_SETTINGS” />  
  8.     <uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />  
  9.     <uses-permission android:name=”android.permission.BIND_ACCESSIBILITY_SERVICE” />  
  10.     <uses-permission android:name=”android.permission.GET_TASKS” />  
  11.     <uses-permission android:name=”android.permission.REORDER_TASKS” />  
  12.     <uses-permission android:name=”android.permission.WAKE_LOCK” />  
  13.   
  14.     <application  
  15.         android:allowBackup=”true”  
  16.         android:icon=”@mipmap/ic_launcher”  
  17.         android:label=”@string/app_name”  
  18.         android:supportsRtl=”true”  
  19.         android:theme=”@style/AppTheme”>  
  20.         <activity android:name=”.MainActivity”>  
  21.             <intent-filter>  
  22.                 <action android:name=”android.intent.action.MAIN” />  
  23.   
  24.                 <category android:name=”android.intent.category.LAUNCHER” />  
  25.             </intent-filter>  
  26.         </activity>  
  27.   
  28.         <service  
  29.             android:name=”.AutoReplyService”  
  30.             android:enabled=”true”  
  31.             android:exported=”true”  
  32.             android:label=”@string/app_name”  
  33.             android:permission=”android.permission.BIND_ACCESSIBILITY_SERVICE”>  
  34.             <intent-filter>  
  35.                 <action android:name=”android.accessibilityservice.AccessibilityService”/>  
  36.             </intent-filter>  
  37.   
  38.             <meta-data  
  39.                 android:name=”android.accessibilityservice”  
  40.                 android:resource=”@xml/auto_reply_service_config”/>  
  41.         </service>  
  42.     </application>  
  43. </manifest>  
<?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服务,因为很有可能造成一些安全问题,所以,自己动手写就安全多了嘛。

github项目地址:
WcAutoReply


原文链接:http://www.jianshu.com/p/f67e950d84f7
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值