温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android辅助功如何实现自动抢红包

发布时间:2021-07-10 10:30:34 来源:亿速云 阅读:205 作者:小新 栏目:移动开发

这篇文章主要介绍Android辅助功如何实现自动抢红包,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一、描述

最近看到同事有用抢红包的软件,就想看看抢红包的具体实现是如何的,所以了解了一下,有用辅助功能实现的,所以在下面的示例中会展示一个抢红包的小Demo,附带源码抢红包源码。

二、效果图

Android辅助功如何实现自动抢红包

在桌面收到红包进行抢

Android辅助功如何实现自动抢红包

在聊天页面收到口令红包

三、AccessibilityService使用

创建辅助服务类,继承AccessibilityService,实现两个接口,接收系统的事件

public class MyService extends AccessibilityService {  @Override  public void onAccessibilityEvent(AccessibilityEvent event) {     }  @Override  public void onInterrupt() {     } }

辅助服务的配置文件,配置事件,在 res/xml下创建accessibility_service_info.xml

//具体属性的说明在第5点有说明 <?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"  android:description="@string/accessibility_service_description"  android:accessibilityEventTypes="typeAllMask"  android:accessibilityFeedbackType="feedbackGeneric"  android:notificationTimeout="100"  android:accessibilityFlags="flagDefault"  android:canRetrieveWindowContent="true"  android:packageNames="top.cokernut.sample"  android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />

注册Service辅助服务,并且为Service附加上第二步创建的xml,看清除下面的一些属性,必须要加,如果有的没加的话是没效果的

<service    android:name=".MyService"    android:label="辅助功能"    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/accessibility_service_info" />   </service>

4 清单文件中添加权限

 <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />

辅助服务配置文件xml属性说明:

//是否可以检索整个层级下的内容 android:canRetrieveWindowContent="true"级下的信息 //事件通知触发点,比如窗口打开,滑动,焦点变化,长按等。 android:accessibilityEventTypes="typeAllMask" #TYPES_ALL_MASK:所有类型 #TYPE_VIEW_CLICKED :单击 #TYPE_VIEW_LONG_CLICKED :长按 #TYPE_VIEW_SELECTED :选中 #TYPE_VIEW_FOCUSED :获取焦点 #TYPE_VIEW_TEXT_CHANGED :文字改变 #TYPE_WINDOW_STATE_CHANGED :窗口状态改变 //表示反馈方式,比如是语音播放,还是震动 android:accessibilityFeedbackType="feedbackGeneric" //接受事件的时间间隔,通常将其设置为100即可. android:notificationTimeout="100" //表示该服务是用来单独监听哪个应用的产生的事件,其他的都会过滤,如果不填就是对所有的应用进行监听,填入包名即可。 android:packageNames="top.cokernut.sample" //在代码中我们就可以通过node节点来getViewIdResourceName()获取对应的节点的id android:accessibilityFlags="flagDefault"

提供一个AccessibilityService的基类,集成了一些常用方法:

public class BaseAccessibilityService extends AccessibilityService {  private AccessibilityManager mAccessibilityManager;  private Context mContext;  private static BaseAccessibilityService mInstance;  public void init(Context context) {   mContext = context.getApplicationContext();   mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);  }  public static BaseAccessibilityService getInstance() {   if (mInstance == null) {    mInstance = new BaseAccessibilityService();   }   return mInstance;  }  /**   * Check当前辅助服务是否启用   *   * @param serviceName serviceName   * @return 是否启用   */  private boolean checkAccessibilityEnabled(String serviceName) {   List<AccessibilityServiceInfo> accessibilityServices =     mAccessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC);   for (AccessibilityServiceInfo info : accessibilityServices) {    if (info.getId().equals(serviceName)) {     return true;    }   }   return false;  }  /**   * 前往开启辅助服务界面   */  public void goAccess() {   Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   mContext.startActivity(intent);  }  /**   * 模拟点击事件   *   * @param nodeInfo nodeInfo   */  public void performViewClick(AccessibilityNodeInfo nodeInfo) {   if (nodeInfo == null) {    return;   }   while (nodeInfo != null) {    if (nodeInfo.isClickable()) {     nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);     break;    }    nodeInfo = nodeInfo.getParent();   }  }  /**   * 模拟返回操作   */  public void performBackClick() {   try {    Thread.sleep(500);   } catch (InterruptedException e) {    e.printStackTrace();   }   performGlobalAction(GLOBAL_ACTION_BACK);  }  /**   * 模拟下滑操作   */  public void performScrollBackward() {   try {    Thread.sleep(500);   } catch (InterruptedException e) {    e.printStackTrace();   }   performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);  }  /**   * 模拟上滑操作   */  public void performScrollForward() {   try {    Thread.sleep(500);   } catch (InterruptedException e) {    e.printStackTrace();   }   performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);  }  /**   * 查找对应文本的View   *   * @param text text   * @return View   */  public AccessibilityNodeInfo findViewByText(String text) {   return findViewByText(text, false);  }  /**   * 查找对应文本的View   *   * @param text  text   * @param clickable 该View是否可以点击   * @return View   */  public AccessibilityNodeInfo findViewByText(String text, boolean clickable) {   AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();   if (accessibilityNodeInfo == null) {    return null;   }   List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);   if (nodeInfoList != null && !nodeInfoList.isEmpty()) {    for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {     if (nodeInfo != null && (nodeInfo.isClickable() == clickable)) {      return nodeInfo;     }    }   }   return null;  }  /**   * 查找对应ID的View   *   * @param id id   * @return View   */  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)  public AccessibilityNodeInfo findViewByID(String id) {   AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();   if (accessibilityNodeInfo == null) {    return null;   }   List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);   if (nodeInfoList != null && !nodeInfoList.isEmpty()) {    for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {     if (nodeInfo != null) {      return nodeInfo;     }    }   }   return null;  }  public void clickTextViewByText(String text) {   AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();   if (accessibilityNodeInfo == null) {    return;   }   List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);   if (nodeInfoList != null && !nodeInfoList.isEmpty()) {    for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {     if (nodeInfo != null) {      performViewClick(nodeInfo);      break;     }    }   }  }  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)  public void clickTextViewByID(String id) {   AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();   if (accessibilityNodeInfo == null) {    return;   }   List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);   if (nodeInfoList != null && !nodeInfoList.isEmpty()) {    for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {     if (nodeInfo != null) {      performViewClick(nodeInfo);      break;     }    }   }  }  /**   * 模拟输入   *   * @param nodeInfo nodeInfo   * @param text  text   */  public void inputText(AccessibilityNodeInfo nodeInfo, String text) {   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {    Bundle arguments = new Bundle();    arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);    nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);   } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);    ClipData clip = ClipData.newPlainText("label", text);    clipboard.setPrimaryClip(clip);    nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);    nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);   }  }  @Override  public void onAccessibilityEvent(AccessibilityEvent event) {  }  @Override  public void onInterrupt() {  } }

四、QQ抢红包

(一)抢红包流程:

  1. 通知栏收到QQ的消息,发现是QQ红包,模拟点击消息进入聊天页面

  2. 检索页面上的所有元素,发现有包含“点击拆开”的字眼,就模拟点击打开红包窗口

  3. 一两秒后执行Back操作,关闭红包窗口。

  4. 继续等待消息来到。

(二)实现功能:

  1. 锁屏抢红包(不可以有密码或者图案之类的锁屏)

  2. 口令红包,自动输入口令并且发送

  3. 抢完红包后,自动回复感谢语,可在红包设置里自行设置内容

  4. 其他的功能就没继续往下做了,知道方法,其他都可能慢慢研究出来。

(三)抢红包辅助功能类,注释都写好了,很好理解,类中有用到QQConstant类,在第四点贴出了代码

/**  * 描述:QQ抢红包服务  * 作者:卜俊文  * 邮箱:344176791@qq.com  * 日期:2017/11/6 上午9:25  */ public class EnvelopeService extends BaseAccessibilityService {  //锁屏、解锁相关  private KeyguardManager.KeyguardLock kl;  //唤醒屏幕相关  private PowerManager.WakeLock wl = null;  private long delayTime = 0;//延迟抢的时间  /**   * 描述:所有事件响应的时候会回调   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/6 上午9:26   */  @Override  public void onAccessibilityEvent(AccessibilityEvent event) {   //验证抢红包的开关   if (!invalidEnable()) {    return;   }   //事件类型   int eventType = event.getEventType();   //获取包名   CharSequence packageName = event.getPackageName();   if (TextUtils.isEmpty(packageName)) {    return;   }   switch (eventType) {    //状态栏变化    case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:     if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) {      //处理状态栏上QQ的消息,如果是红包就跳转过去      progressQQStatusBar(event);     }     break;    //窗口切换的时候回调    case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:    case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:     if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) {      //处理正在QQ聊天窗口页面,有其他群或者人有新的红包提醒,跳转过去。      progressNewMessage(event);      //处理聊天页面的红包      progressQQChat(event);     }     break;   }  }  /**   * 描述:处理新消息   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/3 下午11:21   */  private void progressNewMessage(AccessibilityEvent event) {   if (event == null) {    return;   }   AccessibilityNodeInfo source = event.getSource();   if (source == null) {    return;   }   //根据event的source里的text,来判断这个消息是否包含[QQ红包]的字眼,有的话就跳转过去   CharSequence text = source.getText();   if (!TextUtils.isEmpty(text) && text.toString().contains(QQConstant.QQ_ENVELOPE_KEYWORD)) {    performViewClick(source);   }  }  /**   * 描述:验证抢红包是否开启   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/3 下午4:57   */  private boolean invalidEnable() {   return SettingConfig.getInstance().getReEnable();  }  /**   * 描述:处理QQ状态栏   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/1 下午1:49   */  public void progressQQStatusBar(AccessibilityEvent event) {   List<CharSequence> text = event.getText();   //开始检索界面上是否有QQ红包的文本,并且他是通知栏的信息   if (text != null && text.size() > 0) {    for (CharSequence charSequence : text) {     if (charSequence.toString().contains(QQConstant.QQ_ENVELOPE_KEYWORD)) {      //说明存在红包弹窗,马上进去      if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {       Notification notification = (Notification) event.getParcelableData();       if (notification == null) {        return;       }       PendingIntent pendingIntent = notification.contentIntent;       if (pendingIntent == null) {        return;       }       try {        //要跳转之前,先进行解锁屏幕,然后再跳转,有可能你现在屏幕是锁屏状态,先进行解锁,然后打开页面,有密码的可能就不行了        wakeUpAndUnlock(MyApp.context);        //跳转        pendingIntent.send();       } catch (PendingIntent.CanceledException e) {        e.printStackTrace();       }      }     }    }   }  }  /**   * 描述:处理QQ聊天红包   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/1 下午1:56   */  public void progressQQChat(AccessibilityEvent event) {   if (TextUtils.isEmpty(event.getClassName())) {    return;    //如果当前页面是聊天页面或者当前的描述信息是"返回消息界面",就肯定是对话页面   }   //验证当前事件是否符合查询页面上的红包   if (!invalidEnvelopeUi(event)) {    return;   }   //延迟点击红包,防止被检测到开了抢红包,不过感觉还是感觉会被检测到,应该有的效果吧...   try {    Thread.sleep(delayTime);   } catch (InterruptedException e) {    e.printStackTrace();   }   //普通红包,检索点击拆开的字眼。   List<AccessibilityNodeInfo> envelope = findViewListByText(QQConstant.QQ_CLICK_TAKE_APART, false);   //处理普通红包   progressNormal(envelope);   //口令红包,检索口令红包的字眼。   List<AccessibilityNodeInfo> passwordList = findViewListByText(QQConstant.QQ_CLICK_PASSWORD_DIALOG, false);   //处理口令红包   progressPassword(passwordList);  }  /**   * 描述:验证是否现在是在聊天页面,可以进行抢红包处理   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/3 上午11:52   *   * @param event   */  public boolean invalidEnvelopeUi(AccessibilityEvent event) {   //判断类名是否是聊天页面   if (!QQConstant.QQ_IM_CHAT_ACTIVITY.equals(event.getClassName().toString())) {    return true;   }   //判断页面中的元素是否有点击拆开的文本,有就返回可以进行查询了   int recordCount = event.getRecordCount();   if (recordCount > 0) {    for (int i = 0; i < recordCount; i++) {     AccessibilityRecord record = event.getRecord(i);     if (record == null) {      break;     }     List<CharSequence> text = record.getText();     if (text != null && text.size() > 0 && text.contains(QQConstant.QQ_CLICK_TAKE_APART)) {      //如果文本中有点击拆开的字眼,就返回可以进行查询了      return true;     }    }   }   return false;  }  /**   * 回到系统桌面   */  private void back2Home(int time) {   try {    Thread.sleep(time);   } catch (InterruptedException e) {    e.printStackTrace();   }   Intent home = new Intent(Intent.ACTION_MAIN);   home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   home.addCategory(Intent.CATEGORY_HOME);   startActivity(home);  }  /**   * 描述:处理普通红包   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/1 下午5:02   */  public void progressNormal(List<AccessibilityNodeInfo> passwordList) {   if (passwordList != null && passwordList.size() > 0) {    for (AccessibilityNodeInfo accessibilityNodeInfo : passwordList) {     if (accessibilityNodeInfo != null && !TextUtils.isEmpty(accessibilityNodeInfo.getText()) && QQConstant.QQ_CLICK_TAKE_APART.equals(accessibilityNodeInfo.getText().toString())) {      //点击拆开红包      performViewClick(accessibilityNodeInfo);      //回复感谢信息,根据配置文件中配置的回复信息回复      String reReplyMessage = SettingConfig.getInstance().getReReplyMessage();      if (!TextUtils.isEmpty(reReplyMessage)) {       replyMessage(reReplyMessage);      }     }    }    //最后延迟事件触发返回事件,关闭红包页面    performBackClick(1200);   }  }  /**   * 描述:处理口令红包   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/1 下午4:58   *   * @param passwordList   */  public void progressPassword(List<AccessibilityNodeInfo> passwordList) {   if (passwordList != null && passwordList.size() > 0) {    for (AccessibilityNodeInfo accessibilityNodeInfo : passwordList) {     if (accessibilityNodeInfo != null && !TextUtils.isEmpty(accessibilityNodeInfo.getText()) && QQConstant.QQ_CLICK_PASSWORD_DIALOG.equals(accessibilityNodeInfo.getText().toString())) {      //如果口令红包存在,就在输入框中进行输入,然后发送      AccessibilityNodeInfo parent = accessibilityNodeInfo.getParent();      if (parent != null) {       CharSequence contentDescription = parent.getContentDescription();       if (!TextUtils.isEmpty(contentDescription)) {        //1. 获取口令        String key = (String) contentDescription;        if (key.contains(",") && key.contains("口令:")) {         key = key.substring(key.indexOf("口令:") + 3, key.lastIndexOf(","));        }        Log.e("口令", key);        //2. 填写口令到编辑框上然后进行发送        replyMessage(key);        //返回,关闭红包页面        performBackClick(1200);       }      }     }    }   }  }  /**   * 唤醒屏幕并解锁权限   * <uses-permission android:name="android.permission.WAKE_LOCK" />   */  @SuppressLint("Wakelock")  @SuppressWarnings("deprecation")  public void wakeUpAndUnlock(Context context) {   // 点亮屏幕   wl.acquire();   // 释放   wl.release();   // 解锁   kl.disableKeyguard();  }  /**   * 描述:回复消息,无延迟   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/3 下午5:10   */  public void replyMessage(String key) {   replyMessage(key, 0);  }  /**   * 描述:回复消息   * 作者:卜俊文   * 邮箱:344176791@qq.com   * 日期:2017/11/3 下午5:10   */  public void replyMessage(String key, int time) {   //延迟   if (time > 0) {    try {     Thread.sleep(time);    } catch (InterruptedException e) {     e.printStackTrace();    }   }   //获取QQ聊天页面输入框   AccessibilityNodeInfo chat_edit = findViewByID(QQConstant.QQ_CHAT_MESSAGE_INPUT);   if (chat_edit != null) {    //把口令粘贴到输入框中    pastaText(chat_edit, MyApp.context, key);    //获取QQ聊天页面发送消息按钮    AccessibilityNodeInfo sendMessage = findViewByID(QQConstant.QQ_CHAT_MESSAGE_SEND);    //然后就按下发送按钮    if (sendMessage != null && Button.class.getName().equals(sendMessage.getClassName())) {     performViewClick(sendMessage);    }   }  }  @Override  public void onInterrupt() {  }  @Override  protected void onServiceConnected() {   super.onServiceConnected();   // 获取电源管理器对象   PowerManager pm = (PowerManager) MyApp.context     .getSystemService(Context.POWER_SERVICE);   // 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag   wl = pm.newWakeLock(     PowerManager.ACQUIRE_CAUSES_WAKEUP       | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");   KeyguardManager km = (KeyguardManager) MyApp.context.getSystemService(Context.KEYGUARD_SERVICE);   kl = km.newKeyguardLock("unLock");   //初始化屏幕的监听   ScreenListener screenListener = new ScreenListener(MyApp.context);   screenListener.begin(new ScreenListener.ScreenStateListener() {    @Override    public void onScreenOn() {     Log.e("ScreenListener", "屏幕打开了");    }    @Override    public void onScreenOff() {     //在屏幕关闭的时候,进行锁屏,不执行的话,锁屏就失效了,因为要实现锁屏状态下也可以进行抢红包。     Log.e("ScreenListener", "屏幕关闭了");     if (kl != null) {      kl.disableKeyguard();      kl.reenableKeyguard();     }    }    @Override    public void onUserPresent() {     Log.e("ScreenListener", "解锁了");    }   });  }  @Override  public void onDestroy() {   super.onDestroy();  } }

(四)QQ辅助服务里有用到的常量

public class QQConstant {  //QQ的应用包名  public static final String QQ_PACKAGE_NAME = "com.tencent.mobileqq";  //状态栏红包关键字  public static final String QQ_ENVELOPE_KEYWORD = "[QQ红包]";  //QQ聊天页面  public static final String QQ_IM_CHAT_ACTIVITY = "com.tencent.mobileqq.activity.SplashActivity";  //点击拆开  public static final String QQ_CLICK_TAKE_APART = "点击拆开";  //口令红包  public static final String QQ_CLICK_PASSWORD_DIALOG = "口令红包";  //聊天页面,输入框ID  public static final String QQ_CHAT_MESSAGE_INPUT = "com.tencent.mobileqq:id/input";  //聊天页面,发送按钮  public static final String QQ_CHAT_MESSAGE_SEND = "com.tencent.mobileqq:id/fun_btn"; }

五、红包问题

用的时候偶尔会被QQ检测到用了红包插件,可能是因为抢的速度太快,导致数据不符合正常的点击时间,我有加入一个延迟时间,不知道有没有效果,如果有知道的也可以留言,谢谢。

在QQ的主页面上,收到消息的时候通知栏是不会通知的,所以这里不能进行解析通知栏跳转聊天页面,没有找到什么元素可以告诉我怎么进入红包的聊天页面,如果有知道的可以留言,谢谢。

这种辅助服务的方式抢红包,进入聊天页面后,他检索字段只会检索当前页面可视的元素,某些红包要是在聊天记录上面看不见的,需要滑动上去才可以触发解析红包,不过一般不会一次性10个红包都发出来吧,嘿嘿。

以上是“Android辅助功如何实现自动抢红包”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI