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

推荐阅读:Android中微信抢红包插件原理解析及开发思路

抢红包的原理都差不多,一般是用Android的辅助功能(AccessibilityService类)先监听通知栏事件或窗口变化事件来查找红包关键字然后去模拟点击或打开红包。

下面附上源码,程序已实现自动抢红包,锁屏黑屏状态自动解锁亮屏,Android4.X测试通过。函数具体功能请看详细注释。
注:在聊天界面收到红包不会自动打开,因为通知栏没有消息提示从而监听不了,此时只需手动点一下即可。其他未知情况请自行用LogCat调试,源码已经有相关的调试信息。软件仅供学习娱乐。

<pre style="margin-top: 0px; margin-bottom: 0px;"><span style="font-family: Arial, Helvetica, sans-serif; color: rgb(192, 192, 192);"></span><pre style="margin-top: 0px; margin-bottom: 0px;">import java.util.Calendar;
import java.util.List;
import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.PowerManager;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
public class Demo extends AccessibilityService {
private boolean canGet = false;//能否点击红包
private boolean enableKeyguard = true;//默认有屏幕锁
//窗口状态
private static final int WINDOW_NONE = 0;
private static final int WINDOW_LUCKYMONEY_RECEIVEUI = 1;
private static final int WINDOW_LUCKYMONEY_DETAIL = 2;
private static final int WINDOW_LAUNCHER = 3;
private static final int WINDOW_OTHER = -1;
//当前窗口
private int mCurrentWindow = WINDOW_NONE;
//锁屏、解锁相关
private KeyguardManager km;
private KeyguardLock kl;
//唤醒屏幕相关
private PowerManager pm;
private PowerManager.WakeLock wl = null;
//播放提示声音
private MediaPlayer player;
public void playSound(Context context) {
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
//夜间不播放提示音
if(hour > 7 && hour < 22) {
player.start();
}
}
//唤醒屏幕和解锁
private void wakeAndUnlock(boolean unLock)
{
if(unLock)
{
//若为黑屏状态则唤醒屏幕
if(!pm.isScreenOn()) {
//获取电源管理器对象,ACQUIRE_CAUSES_WAKEUP这个参数能从黑屏唤醒屏幕
wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "bright");
//点亮屏幕
wl.acquire();
Log.i("demo", "亮屏");
}
//若在锁屏界面则解锁直接跳过锁屏
if(km.inKeyguardRestrictedInputMode()) {
//设置解锁标志,以判断抢完红包能否锁屏
enableKeyguard = false;
//解锁
kl.disableKeyguard();
Log.i("demo", "解锁");
}
}
else
{
//如果之前解过锁则加锁以恢复原样
if(!enableKeyguard) {
//锁屏
kl.reenableKeyguard();
Log.i("demo", "加锁");
}
//若之前唤醒过屏幕则释放之使屏幕不保持常亮
if(wl != null) {
wl.release();
wl = null;
Log.i("demo", "关灯");
}
}
}
//通过文本查找节点
public AccessibilityNodeInfo findNodeInfosByText(AccessibilityNodeInfo nodeInfo, String text) {
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(text);
if(list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
//模拟点击事件
public void performClick(AccessibilityNodeInfo nodeInfo) {
if(nodeInfo == null) {
return;
}
if(nodeInfo.isClickable()) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else {
performClick(nodeInfo.getParent());
}
}
//模拟返回事件
public void performBack(AccessibilityService service) {
if(service == null) {
return;
}
service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
}
//实现辅助功能
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
Log.i("demo", Integer.toString(eventType));
switch (eventType) {
//第一步:监听通知栏消息
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
List<CharSequence> texts = event.getText();
if (!texts.isEmpty()) {
for (CharSequence text : texts) {
String content = text.toString();
Log.i("demo", "text:"+content);
//收到红包提醒
if (content.contains("[微信红包]")||content.contains("[QQ红包]")) {
//模拟打开通知栏消息
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
//播放提示音
playSound(this);
//若是微信红包则解锁并自动打开,若是qq红包则只提示并跳转到有红包的聊天界面,暂未实现qq红包自动领取功能
if(content.contains("[微信红包]"))
wakeAndUnlock(true);
Log.i("demo", "canGet=true");
canGet = true;
try {
Notification notification = (Notification) event.getParcelableData();
PendingIntent pendingIntent = notification.contentIntent;
pendingIntent.send();
} catch (CanceledException e) {
e.printStackTrace();
}
}
break;
}
}
}
break;
//第二步:监听是否进入微信红包消息界面
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
String className = event.getClassName().toString();
if (className.equals("com.tencent.mm.ui.LauncherUI")) {
mCurrentWindow = WINDOW_LAUNCHER;
//开始抢红包
Log.i("demo", "准备抢红包...");
getPacket();
} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) {
mCurrentWindow = WINDOW_LUCKYMONEY_RECEIVEUI;
//开始打开红包
Log.i("demo", "打开红包");
openPacket();
wakeAndUnlock(false);
} else if(className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) {
mCurrentWindow = WINDOW_LUCKYMONEY_DETAIL;
//返回以方便下次收红包
Log.i("demo", "返回");
performBack(this);
} else {
mCurrentWindow = WINDOW_OTHER;
}
break;
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
if(mCurrentWindow != WINDOW_LAUNCHER) { //不在聊天界面或聊天列表,不处理
return;
}
if(canGet) {
getPacket();
}
break;
}
}
//找到红包并点击
@SuppressLint("NewApi")
private void getPacket() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo == null) {
return;
}
// 找到领取红包的点击事件
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
if(list != null ) {
if(list.isEmpty()) {
Log.i("demp", "领取列表为空");
// 从消息列表查找红包
AccessibilityNodeInfo node = findNodeInfosByText(nodeInfo, "[微信红包]");
if(node != null) {
canGet = true;
performClick(node);
}
}
else {
if(canGet) {
//最新的红包领起
AccessibilityNodeInfo node = list.get(list.size() - 1);
performClick(node);
Log.i("demo", "canGet=false");
canGet = false;
}
}
}
}
//打开红包
@SuppressLint("NewApi")
private void openPacket() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if(nodeInfo == null) {
return;
}
Log.i("demo", "查找打开按钮...");
AccessibilityNodeInfo targetNode = null;
//如果红包已经被抢完则直接返回
targetNode = findNodeInfosByText(nodeInfo, "看看大家的手气");
if(targetNode != null) {
performBack(this);
return;
}
//通过组件名查找开红包按钮,还可通过组件id直接查找但需要知道id且id容易随版本更新而变化,旧版微信还可直接搜“開”字找到按钮
if(targetNode == null) {
Log.i("demo", "打开按钮中...");
for (int i = 0; i < nodeInfo.getChildCount(); i++) {
AccessibilityNodeInfo node = nodeInfo.getChild(i);
if("android.widget.Button".equals(node.getClassName())) {
targetNode = node;
break;
}
}
}
//若查找到打开按钮则模拟点击
if(targetNode != null) {
final AccessibilityNodeInfo n = targetNode;
performClick(n);
}
}
@Override
public void onInterrupt() {
Toast.makeText(this, "抢红包服务被中断啦~", Toast.LENGTH_LONG).show();
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.i("demo", "开启");
//获取电源管理器对象
pm=(PowerManager)getSystemService(Context.POWER_SERVICE);
//得到键盘锁管理器对象
km= (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
//初始化一个键盘锁管理器对象
kl = km.newKeyguardLock("unLock");
//初始化音频
player = MediaPlayer.create(this, R.raw.songtip_m);

Toast.makeText(this, "_已开启抢红包服务_", Toast.LENGTH_LONG).show();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("demo", "关闭");
wakeAndUnlock(false);
Toast.makeText(this, "_已关闭抢红包服务_", Toast.LENGTH_LONG).show();
}
}

AndroidManifest.xml中声明相关服务和权限

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<pre name="code" class="html"><service
android:name="com.example.test.Demo" 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="@layout/accessibility_config"/></service></application>

accessibility_config.xml服务配置内容如下

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

其中description为辅助功能的描述内容,packageNames为监听的程序包名,此处只监听微信和QQ的accessibilityEventTypes

以上所述是针对Android辅助功能AccessibilityService与抢红包辅助的相关知识,希望对大家有所帮助。

(0)

相关推荐

  • Android Service 服务不被杀死的妙招

    Service是android 系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互. Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理. 从Android官方文档中,我们知道onStartCommand有4种int返回值,首先简单地讲讲int返回值的作用.

  • Android中实现开机自动启动服务(service)实例

    最近在将 HevSocks5Client 移植到 Android 上了,在经过增加 signalfd 和 timerfd 相关的系统调用支持后,就可以直接使用 NDK 编译出 executable 了.直接的 native exectuable 在 Android 系统总还是不太方便用哦.还是做成一个 apk 吧,暂定只写一个 service 并开机自动启用,无 activity 的. Java 中调用 native 程序我选择使用 JNI 方式,直接在 JNI_OnLoad 方法中调用 pth

  • 在Android中 获取正在运行的Service 实例

    public class ServiceList extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); ActivityManager activityManger = (ActivityManager) getSystemService(ACTIV

  • android开发教程之开机启动服务service示例

    个例子实现的功能是:1,安装程序后看的一个Activity程序界面,里面有个按钮,点击按钮就会启动一个Service服务,此时在设置程序管理里面会看的有个Activity和一个Service服务运行2,如果手机关机重启,会触发你的程序里面的Service服务,当然,手机启动后是看不到你的程序界面.好比手机里面自带的闹钟功能,手机重启看不到闹钟设置界面只是启动服务,时间到了,闹钟就好响铃提醒. 程序代码是: 首先要有一个用于开机启动的Activity,给你们的按钮设置OnClickListener

  • Android应用程序四大组件之使用AIDL如何实现跨进程调用Service

    一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentProvider实现了不同应用之间的跨进程调用,但ContentProvider主要是提供数据的共享(如sqlite数据库),那么我们希望跨进程调用服务(Service)呢?Android系统采用了远程过程调用(RPC)方式来实现.与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言

  • 解析Android中如何做到Service被关闭后又自动启动的实现方法

    首先要说的是,用户可能把这种做法视为流氓软件.大部分时候,程序员也不想把软件做成流氓软件,没办法,领导说了算. 我们在使用某些Android应用的时候,可能会发现安装了某应用以后,会有一些服务也会随之运行.而且,这些服务每次都会随着手机开机而启动.有的服务做的更绝,当用户在运行的服务中手动停止该服务以后,过了一段时间,服务又自动运行了.虽然,从用户的角度来说,这种方式比较流氓.但是,从程序员的角度来说,这是如何做到的呢?经过研究,我发现有一种方式是可以实现的.下面就和大家分享. 先简单介绍,一会

  • android中soap协议使用(ksoap调用webservice)

    如下面代码所示: 复制代码 代码如下: SoapObject request  = new SoapObject(serviceNamespace, methodName); SoapObject构造函数的两个参数含义为: serviceNamespace – 你的webservice的命名空间,既可以是 http://localhost:8088/flickrBuddy/services/Buddycast这样的,也可以是 urn:PI/DevCentral/SoapService这样的: m

  • Android中bindService基本使用方法概述

    Android中有两种主要方式使用Service,通过调用Context的startService方法或调用Context的bindService方法,本文只探讨纯bindService的使用,不涉及任何startService方法调用的情况.如果想了解startService相关的使用,请参见<Android中startService基本使用方法概述>. bindService启动服务的特点 相比于用startService启动的Service,bindService启动的服务具有如下特点:

  • Android中Service的全面总结

    全面总结Android Service的使用方法,具体内容如下 1.Service的种类 按运行地点分类: 其实remote服务还是很少见的,并且一般都是系统服务. 按运行类型分类: 有同学可能会问,后台服务我们可以自己创建 ONGOING 的 Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成

  • Android中使用IntentService创建后台服务实例

    IntentService提供了在单个后台线程运行操作的简单结构.这允许它操作耗时操作,而不影响UI响应.同样,IntentService也不影响UI生命周期事件,所以,它在某些可能关闭AsyncTask的情况下,仍会继续运行(实测在Activity的onDestory里写AsyncTask无法运行). IntentService有如下限制: 1.它不能直接影响UI.要把结果反映给UI,需要发给Activity 2.工作请求会顺序运行.如果一个操作未结束,后面发送的操作必须等它结束(单线程) 3

随机推荐