推荐阅读: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与抢红包辅助的相关知识,希望对大家有所帮助。
本文向大家介绍Android辅助功能实现自动抢红包(附源码),包括了Android辅助功能实现自动抢红包(附源码)的使用技巧和注意事项,需要的朋友参考一下 一、描述 最近看到同事有用抢红包的软件,就想看看抢红包的具体实现是如何的,所以了解了一下,有用辅助功能实现的,所以在下面的示例中会展示一个抢红包的小Demo,附带源码抢红包源码。 二、效果图 在桌面收到红包进行抢 在聊天页面收到口令红包 三、A
为程序制作辅助功能是很重要的。在这里,我们很高兴地向你们介绍Devtron和Spectron。这两个新功能有机会使开发者们让他们的应用程序更加可用。 Electron 应用中有关辅助功能的开发和网站是相似的,因为两者最终使用的都是HTML. 然而, 对于Electron应用, 你不能使用在线的辅助功能审查者, 因为你的应用没有一个URL可以提供给审查者. 然而这些新功能将这些审查工具带到您的Ele
为程序制作辅助功能是很重要的。在这里,我们很高兴地向你们介绍Devtron和Spectron。这两个新功能有机会使开发者们让他们的应用程序更加可用。 Electron 应用中有关辅助功能的开发和网站是相似的,因为两者最终使用的都是HTML. 然而, 对于Electron应用, 你不能使用在线的辅助功能审查者, 因为你的应用没有一个URL可以提供给审查者. 这些功能将会提供一些审查工具给你的Elec
扩展使用者能够根据个人的能力和偏好创建理想的浏览体验。 扩展程序应包括可访问性组件,该组件通过使视力障碍,听力受损,肢体受限和其他残障人士能够访问扩展程序,从而鼓励包容性用户群。 每个人,不仅是有特殊需求的用户,都可以从辅助功能中受益。 视力障碍,肢体受限用户都将从键盘快捷键中受益。 字幕和笔录对聋哑用户至关重要,但也对语言学习者有所帮助。 人们可以通过多种方式与扩展互动。一些用户具有标准的显示器
一般来说,可访问性意味着可用性,内容可访问意味着内容可用。 在软件方面,应用程序可访问意味着应用程序可供所有人使用。 在这里,所有意味着残疾人,视障者或使用屏幕阅读器使用计算机的人或者喜欢使用键盘而不是使用鼠标导航的人。 用键盘导航而不是使用鼠标。 可访问的应用程序称为ARIA(可访问的富Internet应用程序)。 Ext JS中的辅助功能 Ext JS旨在记住它应该适用于所有键盘导航。 它具有
我在文本视图下方有一个水平回收器视图(最近的项目在最右边的位置,最古老的项目在最左边的位置)。一旦辅助功能控件到达文本视图,在向右滑动时,它会聚焦在回收器视图的最左边的项目(即第一个项目)。有没有办法我们可以将默认焦点设置为最右边的项目。