Android辅助功能实现自动抢红包(附源码)

一、描述

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

二、效果图

在桌面收到红包进行抢

在聊天页面收到口令红包

三、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个红包都发出来吧,嘿嘿。

六、总结

学习制作了这个项目,也了解了辅助功能的使用,感觉这个还是可以做很多东西的,上面已经贴出了核心代码,要源码的可以点击。抢红包源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 教你一步步实现Android微信自动抢红包

    本文介绍微信自动抢红包的实现方法,主要实现以下几个功能: 1.自动拆开屏幕上出现的红包 2.处于桌面或聊天列表时接收到红包信息时自动进入聊天界面并拆红包 3.日志功能,记录抢红包的详细日志 实现原理 1.利用AccessibilityService辅助服务,监测屏幕内容,实现自动拆红包的目的. 2.利用ActiveAndroid数据库简单记录红包日志 3.利用preference实现监控选项纪录 最终界面 抢红包核心代码 AccessibilityService配置 android:access

  • Android实现微信自动抢红包的程序

    简单实现了微信自动抢红包的服务,原理就是根据关键字找到相应的View, 然后自动点击.主要是用到AccessibilityService这个辅助服务,基本可以满足自动抢红包的功能,但是有些逻辑需要优化,比如,拆完一个红包后,必须手动点击返回键,才能进行下一次自动抢红包. AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="h

  • Android微信自动抢红包插件优化和实现

    又是兴趣系列 网上有很多自动强红包的例子和代码,笔者也是做了一些优化. 先说说自己的两个个优势 1.可以在聊天界面自动强不依赖于通知栏推送 2.可以在屏幕熄灭的时候的时候点亮屏幕自动抢(目前只测过flyme) 先上图: 代码传送门: https://github.com/AndroidMsky/WXhongbao 欢迎点星星~ 原理: 通过AccessibilityService监听到状态栏通知,进行模拟点击,获取屏幕中view节点为领取红包的list并且点击最后一个. 如果不通过状态栏通知,通

  • Android辅助功能实现自动抢红包(附源码)

    一.描述 最近看到同事有用抢红包的软件,就想看看抢红包的具体实现是如何的,所以了解了一下,有用辅助功能实现的,所以在下面的示例中会展示一个抢红包的小Demo,附带源码抢红包源码. 二.效果图 在桌面收到红包进行抢 在聊天页面收到口令红包 三.AccessibilityService使用 创建辅助服务类,继承AccessibilityService,实现两个接口,接收系统的事件 public class MyService extends AccessibilityService { @Overr

  • 超简单实现Android自定义Toast示例(附源码)

    Bamboy的自定义Toast,(以下称作"BToast") 特点在于使用简单, 并且自带两种样式: 1)普通的文字样式: 2)带图标样式. 其中图标有√和×两种图标. BToast还有另外一个特点就是: 系统自带Toast采用的是队列的方式,当前Toast消失后,下一个Toast才能显示出来: 而BToast会把当前Toast顶掉, 直接显示最新的Toast. 那么,简单三步,我们现在就开始自定义一下吧! (一).Layout: 要自定义Toast, 首先我们需要一个XML布局. 但

  • 自定义Android六边形进度条(附源码)

    本文实例讲述了Android自定义圆形进度条,分享给大家供大家参考.具体如下: 大家也可以参考这两篇文章进行学习: <自定义Android圆形进度条(附源码)>   <Android带进度的圆形进度条> 运行效果截图如下: 主要代码: package com.sxc.hexagonprogress; import java.util.Random; import android.content.Context; import android.content.res.ColorSta

  • 100行Python代码实现自动抢火车票(附源码)

    前言 又要过年了,今年你不妨自己写一段代码来抢回家的火车票,是不是很Cool.下面话不多说了,来一起看看详细的介绍吧. 先准备好: 12306网站用户名和密码 chrome浏览器及下载chromedriver 下载Python代码,来自网络整理 [点击下载 |  本地下载 ] 代码用的Python+Splinter开发,Splinter是一个使用Python开发的开源Web应用测试工具,它可以帮你实现自动浏览站点和与其进行交互. Splinter官网:http://splinter.readth

  • Android编程实现画板功能的方法总结【附源码下载】

    本文实例讲述了Android编程实现画板功能的方法.分享给大家供大家参考,具体如下: Android实现画板主要有2种方式,一种是用自定义View实现,另一种是通过Canvas类实现.当然自定义View内部也是用的Canvas.第一种方式的思路是,创建一个自定义View(推荐SurfaceView),在自定义View里通过Path对象记录手指滑动的路径调用lineTo()绘制:第二种方式的思路是,先用Canvas绘制一张空的Bitmap,通过ImageView的setImageBitmap()方

  • Android实现一个比相册更高大上的左右滑动特效(附源码)

    目录 实现思路 源码如下: 在Android里面,想要实现一个类似相册的左右滑动效果,我们除了可以用Gallery.HorizontalScrollView.ViewPager等控件,还可以用一个叫做 ViewFlipper 的类来代替实现,它继承于 ViewAnimator.如见其名,这个类是跟动画有关,会将添加到它里面的两个或者多个View做一个动画,然后每次只显示一个子View,通过在 View 之间切换时执行动画,最终达到一个类似相册能左右滑动的效果. 本次功能要实现的两个基本效果 最基

  • 趣味Python实战练习之自动更换桌面壁纸脚本附源码

    目录 前言 目标地址 先是爬虫代码 导入数据 请求数据 解析数据 保存数据 运行代码,查看结果 自动跟换桌面壁纸代码 最后实现效果 前言 发现一个不错的壁纸网站,里面都是超高清的图片,而且还是免费为的. 所以,我打算把这些壁纸都爬取下来,然后在做一个自动跟换桌面壁纸的脚本,这样基本上你一年都可以每天都有不重复桌面了 目标地址 先来看看我们这次的受害者:https://wallhaven.cc/ [付费VIP完整版]只要看了就能学会的教程,80集Python基础入门视频教学 点这里即可免费在线观看

  • 我用Python给班主任写了一个自动阅卷脚本(附源码)

    导语 幼儿园升小学,小学升中学,中学升高中.......... 每个人都要经历的九年义务教育:伴随的都是作业.随堂考.以及每个科目的大大小小的考试.当然小编被考试支配的恐惧以及过去了哈~除了学生考试的压力之外. 有调查发现,目前老师大量的时间被小型考试,如课堂测验.周测等高频次测验的批改客观题.计分.登分等占用,被迫压缩了备课.精准辅导的时间. 今天小编带大家做一款解放教师的自动阅卷系统. 几千张的答题卡扫描录入电脑阅卷系统,老师们只需打开电脑登陆,即可找到自己要批改的那道题. 大大提高了改卷效

  • Android辅助功能AccessibilityService与抢红包辅助

    推荐阅读:Android中微信抢红包插件原理解析及开发思路 抢红包的原理都差不多,一般是用Android的辅助功能(AccessibilityService类)先监听通知栏事件或窗口变化事件来查找红包关键字然后去模拟点击或打开红包. 下面附上源码,程序已实现自动抢红包,锁屏黑屏状态自动解锁亮屏,Android4.X测试通过.函数具体功能请看详细注释. 注:在聊天界面收到红包不会自动打开,因为通知栏没有消息提示从而监听不了,此时只需手动点一下即可.其他未知情况请自行用LogCat调试,源码已经有相

  • Android自定义UI手势密码改进版源码下载

    在之前文章的铺垫下,再为大家分享一篇:Android手势密码,附源码下载,不要错过. 源码下载:http://xiazai.jb51.net/201610/yuanma/androidLock(jb51.net).rar 先看第一张图片的布局文件 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sc

随机推荐