Android辅助功能AccessibilityService与抢红包辅助
推荐阅读:Android中微信抢红包插件原理解析及开发思路
抢红包的原理都差不多,一般是用Android的辅助功能(AccessibilityService类)先监听通知栏事件或窗口变化事件来查找红包关键字然后去模拟点击或打开红包。
下面附上源码,程序已实现自动抢红包,锁屏黑屏状态自动解锁亮屏,Android4.X测试通过。函数具体功能请看详细注释。
注:在聊天界面收到红包不会自动打开,因为通知栏没有消息提示从而监听不了,此时只需手动点一下即可。其他未知情况请自行用LogCat调试,源码已经有相关的调试信息。软件仅供学习娱乐。
<prestyle="margin-top:0px;margin-bottom:0px;"><spanstyle="font-family:Arial,Helvetica,sans-serif;color:rgb(192,192,192);"></span><prestyle="margin-top:0px;margin-bottom:0px;">importjava.util.Calendar; importjava.util.List; importandroid.accessibilityservice.AccessibilityService; importandroid.annotation.SuppressLint; importandroid.app.KeyguardManager; importandroid.app.KeyguardManager.KeyguardLock; importandroid.app.Notification; importandroid.app.PendingIntent; importandroid.app.PendingIntent.CanceledException; importandroid.content.Context; importandroid.media.MediaPlayer; importandroid.os.PowerManager; importandroid.util.Log; importandroid.view.accessibility.AccessibilityEvent; importandroid.view.accessibility.AccessibilityNodeInfo; importandroid.widget.Toast; publicclassDemoextendsAccessibilityService{ privatebooleancanGet=false;//能否点击红包 privatebooleanenableKeyguard=true;//默认有屏幕锁 //窗口状态 privatestaticfinalintWINDOW_NONE=0; privatestaticfinalintWINDOW_LUCKYMONEY_RECEIVEUI=1; privatestaticfinalintWINDOW_LUCKYMONEY_DETAIL=2; privatestaticfinalintWINDOW_LAUNCHER=3; privatestaticfinalintWINDOW_OTHER=-1; //当前窗口 privateintmCurrentWindow=WINDOW_NONE; //锁屏、解锁相关 privateKeyguardManagerkm; privateKeyguardLockkl; //唤醒屏幕相关 privatePowerManagerpm; privatePowerManager.WakeLockwl=null; //播放提示声音 privateMediaPlayerplayer; publicvoidplaySound(Contextcontext){ Calendarcal=Calendar.getInstance(); inthour=cal.get(Calendar.HOUR_OF_DAY); //夜间不播放提示音 if(hour>7&&hour<22){ player.start(); } } //唤醒屏幕和解锁 privatevoidwakeAndUnlock(booleanunLock) { 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","关灯"); } } } //通过文本查找节点 publicAccessibilityNodeInfofindNodeInfosByText(AccessibilityNodeInfonodeInfo,Stringtext){ List<AccessibilityNodeInfo>list=nodeInfo.findAccessibilityNodeInfosByText(text); if(list==null||list.isEmpty()){ returnnull; } returnlist.get(0); } //模拟点击事件 publicvoidperformClick(AccessibilityNodeInfonodeInfo){ if(nodeInfo==null){ return; } if(nodeInfo.isClickable()){ nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); }else{ performClick(nodeInfo.getParent()); } } //模拟返回事件 publicvoidperformBack(AccessibilityServiceservice){ if(service==null){ return; } service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); } //实现辅助功能 @Override publicvoidonAccessibilityEvent(AccessibilityEventevent){ inteventType=event.getEventType(); Log.i("demo",Integer.toString(eventType)); switch(eventType){ //第一步:监听通知栏消息 caseAccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: List<CharSequence>texts=event.getText(); if(!texts.isEmpty()){ for(CharSequencetext:texts){ Stringcontent=text.toString(); Log.i("demo","text:"+content); //收到红包提醒 if(content.contains("[微信红包]")||content.contains("[QQ红包]")){ //模拟打开通知栏消息 if(event.getParcelableData()!=null&&event.getParcelableData()instanceofNotification){ //播放提示音 playSound(this); //若是微信红包则解锁并自动打开,若是qq红包则只提示并跳转到有红包的聊天界面,暂未实现qq红包自动领取功能 if(content.contains("[微信红包]")) wakeAndUnlock(true); Log.i("demo","canGet=true"); canGet=true; try{ Notificationnotification=(Notification)event.getParcelableData(); PendingIntentpendingIntent=notification.contentIntent; pendingIntent.send(); }catch(CanceledExceptione){ e.printStackTrace(); } } break; } } } break; //第二步:监听是否进入微信红包消息界面 caseAccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: StringclassName=event.getClassName().toString(); if(className.equals("com.tencent.mm.ui.LauncherUI")){ mCurrentWindow=WINDOW_LAUNCHER; //开始抢红包 Log.i("demo","准备抢红包..."); getPacket(); }elseif(className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")){ mCurrentWindow=WINDOW_LUCKYMONEY_RECEIVEUI; //开始打开红包 Log.i("demo","打开红包"); openPacket(); wakeAndUnlock(false); }elseif(className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")){ mCurrentWindow=WINDOW_LUCKYMONEY_DETAIL; //返回以方便下次收红包 Log.i("demo","返回"); performBack(this); }else{ mCurrentWindow=WINDOW_OTHER; } break; caseAccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: if(mCurrentWindow!=WINDOW_LAUNCHER){//不在聊天界面或聊天列表,不处理 return; } if(canGet){ getPacket(); } break; } } //找到红包并点击 @SuppressLint("NewApi") privatevoidgetPacket(){ AccessibilityNodeInfonodeInfo=getRootInActiveWindow(); if(nodeInfo==null){ return; } //找到领取红包的点击事件 List<AccessibilityNodeInfo>list=nodeInfo.findAccessibilityNodeInfosByText("领取红包"); if(list!=null){ if(list.isEmpty()){ Log.i("demp","领取列表为空"); //从消息列表查找红包 AccessibilityNodeInfonode=findNodeInfosByText(nodeInfo,"[微信红包]"); if(node!=null){ canGet=true; performClick(node); } } else{ if(canGet){ //最新的红包领起 AccessibilityNodeInfonode=list.get(list.size()-1); performClick(node); Log.i("demo","canGet=false"); canGet=false; } } } } //打开红包 @SuppressLint("NewApi") privatevoidopenPacket(){ AccessibilityNodeInfonodeInfo=getRootInActiveWindow(); if(nodeInfo==null){ return; } Log.i("demo","查找打开按钮..."); AccessibilityNodeInfotargetNode=null; //如果红包已经被抢完则直接返回 targetNode=findNodeInfosByText(nodeInfo,"看看大家的手气"); if(targetNode!=null){ performBack(this); return; } //通过组件名查找开红包按钮,还可通过组件id直接查找但需要知道id且id容易随版本更新而变化,旧版微信还可直接搜“開”字找到按钮 if(targetNode==null){ Log.i("demo","打开按钮中..."); for(inti=0;i<nodeInfo.getChildCount();i++){ AccessibilityNodeInfonode=nodeInfo.getChild(i); if("android.widget.Button".equals(node.getClassName())){ targetNode=node; break; } } } //若查找到打开按钮则模拟点击 if(targetNode!=null){ finalAccessibilityNodeInfon=targetNode; performClick(n); } } @Override publicvoidonInterrupt(){ Toast.makeText(this,"抢红包服务被中断啦~",Toast.LENGTH_LONG).show(); } @Override protectedvoidonServiceConnected(){ 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 publicvoidonDestroy(){ super.onDestroy(); Log.i("demo","关闭"); wakeAndUnlock(false); Toast.makeText(this,"_已关闭抢红包服务_",Toast.LENGTH_LONG).show(); } }
AndroidManifest.xml中声明相关服务和权限
<uses-permissionandroid:name="android.permission.WAKE_LOCK"/> <uses-permissionandroid:name="android.permission.DISABLE_KEYGUARD"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <prename="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><actionandroid:name="android.accessibilityservice.AccessibilityService"/></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@layout/accessibility_config"/></service></application>
accessibility_config.xml服务配置内容如下
<accessibility-servicexmlns: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与抢红包辅助的相关知识,希望对大家有所帮助。