日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

抢红包插件实现原理浅析

發布時間:2023/12/20 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 抢红包插件实现原理浅析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

搶紅包,先看效果圖~

實現自動搶紅包,解決問題有兩點:

一:如何實時監聽發紅包的事件

二:如何在紅包到來的時候自動進入頁面并自動點擊紅包

【zhangke3016 http://blog.csdn.net/zhangke3016】

一、如何獲取紅包到來的事件

為了獲取紅包到來狀態欄的變化,我們要用到一個類:Accessibility

許多Android使用者因為各種情況導致他們要以不同的方式與手機交互。
這包括了有些用戶由于視力上,身體上,年齡上的問題致使他們不能看完整的屏幕或者使用觸屏,也包括了無法很好接收到語音信息和提示的聽力能力比較弱的用戶。
Android提供了Accessibility功能和服務幫助這些用戶更加簡單地操作設備,包括文字轉語音(這個不支持中文),觸覺反饋,手勢操作,軌跡球和手柄操作

OK,了解到這一點,那么接下來就順利點了,首先來看看Accessibility以及AccessibilityService的使用

  • 新建一個類繼承AccessibilityService,并在AndroidManifest文件里注冊它:
  • <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <application> <service android:name="com.zkhb.weixinqinghongbao.service.QiangHongBaoService" 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="@xml/qianghongbao_service_config" /></service> </application>

    在子類QiangHongBaoService里實現幾個重要的重載方法:

    onServiceConnected() - 可選。系統會在成功連接上你的服務的時候調用這個方法,在這個方法里你可以做一下初始化工作,例如設備的聲音震動管理,也可以調用setServiceInfo()進行配置工作。
    onAccessibilityEvent() - 必須。通過這個函數可以接收系統發送來的AccessibilityEvent,接收來的AccessibilityEvent是經過過濾的,過濾是在配置工作時設置的。

    onInterrupt() - 必須。這個在系統想要中斷AccessibilityService返給的響應時會調用。在整個生命周期里會被調用多次。
    onUnbind() - 可選。在系統將要關閉這個AccessibilityService會被調用。在這個方法中進行一些釋放資源的工作。

    然后在/res/xml/qianghongbao_service_config.xml:

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

    二、主要關注點以及如何在紅包到來的時候自動進入頁面并自動點擊紅包

    onAccessibilityEvent方法中監聽狀態欄的變化,主要有:AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED

    在響應窗體以及窗體內容變化時處理相關邏輯,獲取帶微信消息時以下代碼打開消息:

    //將微信的通知欄消息打開Notification notification = (Notification) event.getParcelableData();PendingIntent pendingIntent = notification.contentIntent;try {pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}

    具體代碼網上有很多,一般都是通過:findAccessibilityNodeInfosByTextfindAccessibilityNodeInfosByViewId查找文本或者資源節點進行點擊操作,但新版微信開紅包頁面進行了處理,沒有文本信息,而如果采用:

    (上圖截取是用的DDMS中的 UI Automator Viewer,如圖:Eclipse中:
    或者在sdk的tools目錄下:



    圖中resouces-id這種形式就可能出現這種情況:

    在了解整個核心后,獲取事件不外乎就是通過文本與id判斷,那么就可以將文本改為圖標方式,將id改為動態id(每次顯示都是隨機生成),這樣一來就可以提高外掛的門檻。

    如何進行規避呢,目前我想的是既然開紅包的頁面文本和ID都有可能會變,那我們能不能找個不變的進行判斷呢,考慮過后,我覺得最可能不變的地方就是開紅包這個按鈕的位置,也就是圖中的bounds,于是在思考過后有了下面的處理:

    for (int i = 0; i < nodeInfo.getChildCount(); i++) {//Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());Rect outBounds = new Rect();nodeInfo.getChild(i).getBoundsInScreen(outBounds);int left_dp = px2dip(this, 400);int top_dp = px2dip(this, 1035);int right_dp = px2dip(this, 682);int bottom_dp = px2dip(this, 1320);int left_px = dip2px(this, left_dp);int top_px = dip2px(this, top_dp);int right_px = dip2px(this, right_dp);int bottom_px = dip2px(this, bottom_dp);Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);if(mStandar.contains(outBounds)){Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);break;}}

    這里取的矩形區域要比按鈕區域稍大點,然后判斷到開紅包頁面按鈕是否在我們預先設置的區域內,如果在,我們直接進行點擊開紅包操作:AccessibilityNodeInfo.ACTION_CLICK
    其他比如如何防止重復搶等細節問題,也是要處理的問題。
    好了,直接放下關鍵代碼,僅供參考:

    package com.zkhb.weixinqinghongbao.service;import java.util.Date; import java.util.List;import android.accessibilityservice.AccessibilityService; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardLock; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.os.Build; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Toast;import com.zkhb.weixinqinghongbao.MainActivity; import com.zkhb.weixinqinghongbao.R; import com.zkhb.weixinqinghongbao.entity.HongBaoInfo; import com.zkhb.weixinqinghongbao.util.DateFormatUtils; import com.zkhb.weixinqinghongbao.util.LogUtil;/**** 搶紅包服務*/ @SuppressLint("NewApi") public class QiangHongBaoService extends AccessibilityService {// static final String TAG = "QiangHongBao";/** 微信的包名*/static final String WECHAT_PACKAGENAME = "com.tencent.mm";/** 紅包消息的關鍵字*/static final String HONGBAO_TEXT_KEY = "[微信紅包]";/** 紅包消息的關鍵字*/static final String HONGBAO_TEXT_KEY1 = "微信紅包";private static final int ENVELOPE_RETURN = 0;private static final String LOCK_TAG = "屏幕";Handler handler = new Handler();/** 是否在搶紅包界面里*/ // public boolean isInMM=false;/** 是否可以點擊*/ // public boolean ISCLICKED=false;/** 是否進入過拆紅包界面*/public static boolean ISCOMINQIANGCHB=false;//真正的public static boolean ISCOMINQIANGCHB2=false;//真正的判斷public static boolean ISCOMINQIANGCHB3=false;/** 是否來自通知欄*/private static boolean ISCOMNOTIFY=false;private PowerManager pm;//點亮屏幕private WakeLock mWakeLock;//解鎖鎖定屏幕private KeyguardLock keyguardLock;/**判斷之前用戶是否鎖屏 */private static boolean islock=false;/**通知服務 */private NotificationManager n_manager;public void unlock(){if(pm==null){pm = (PowerManager) getApplication().getSystemService(Context.POWER_SERVICE);}boolean isScreenOn = pm.isScreenOn();//如果為true,則表示屏幕“亮”了,否則屏幕“暗”了。if(!isScreenOn){islock=true;KeyguardManager keyguardManager = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);keyguardLock = keyguardManager.newKeyguardLock(LOCK_TAG);keyguardLock.disableKeyguard();mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, LOCK_TAG); mWakeLock.acquire();}}public void lock(){if(islock){//釋放屏幕常亮鎖if(null != mWakeLock) {mWakeLock.release();}//屏幕鎖定if(keyguardLock!=null){keyguardLock.reenableKeyguard();}}}@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {final int eventType = event.getEventType();LogUtil.info("事件---->" + event);//通知欄事件if(eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {unlock();List<CharSequence> texts = event.getText();if(!texts.isEmpty()) {for(CharSequence t : texts) {String text = String.valueOf(t);if(text.contains(HONGBAO_TEXT_KEY)) {ISCOMNOTIFY=true;ISCOMINQIANGCHB=false;openNotify(event);break;}}}} else if(eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {unlock();openHongBao(event); // AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); // List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("領取紅包"); // if(findAccessibilityNodeInfosByText.isEmpty()){ // isInMM=false; // }else{ // isInMM=true; // } // List<CharSequence> text = event.getText(); // if(text.size()>=0){ // CharSequence charSequence = text.get(0); if(charSequence.equals("微信")){ isInMM=true; }else{ isInMM=false; } // }}else if(eventType==AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && ISCOMNOTIFY){unlock();openHongBao(event);List<AccessibilityNodeInfo> InfoText = getRootInActiveWindow().findAccessibilityNodeInfosByText("領取紅包");if(!InfoText.isEmpty()){checkKey2();ISCOMNOTIFY=false;}}}/*@Overrideprotected boolean onKeyEvent(KeyEvent event) {//return super.onKeyEvent(event);return true;}*/@Overridepublic boolean onUnbind(Intent intent) {Toast.makeText(this, "斷開搶紅包服務", Toast.LENGTH_SHORT).show();ISCOMINQIANGCHB=false;islock=false;ISCOMINQIANGCHB2=false;ISCOMINQIANGCHB3=false;ISCOMNOTIFY=false;setNotification("已關閉搶紅包小助手服務~~",Notification.FLAG_AUTO_CANCEL,"已關閉搶紅包小助手服務~~~");return super.onUnbind(intent);}@Overridepublic void onInterrupt() {Toast.makeText(this, "中斷搶紅包服務", Toast.LENGTH_SHORT).show();}@Overrideprotected void onServiceConnected() {super.onServiceConnected();ISCOMINQIANGCHB=false;ISCOMINQIANGCHB2=false;ISCOMINQIANGCHB3=false;islock=false;ISCOMNOTIFY=false;setNotification("已開啟搶紅包小助手服務~~",Notification.FLAG_NO_CLEAR,"已開啟搶紅包小助手服務~~~");Toast.makeText(this, "連接搶紅包服務", Toast.LENGTH_SHORT).show();}private void setNotification(String content,int flags,String title) {if(n_manager==null){n_manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);}n_manager.cancelAll();Notification notification=new Notification(R.drawable.ic_launcher, content, System.currentTimeMillis()); // notification.defaults |= Notification.DEFAULT_VIBRATE; // long[] vibrate = {0,100,200,300}; //0毫秒后開始振動,振動100毫秒后停止,再過200毫秒后再次振動300毫秒 // notification.vibrate=vibrate;notification.flags |= flags; //表明在點擊了通知欄中的"清除通知"后,此通知不清除,Intent notificationIntent = new Intent(this,MainActivity.class); //點擊該通知后要跳轉的ActivityPendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),0,notificationIntent,0);notification.setLatestEventInfo(getApplicationContext(), title, "進入微信搶紅包~~", contentIntent);n_manager.notify(0, notification);}private void sendNotifyEvent(){AccessibilityManager manager= (AccessibilityManager)getSystemService(ACCESSIBILITY_SERVICE);if (!manager.isEnabled()) {return;}AccessibilityEvent event=AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);event.setPackageName(WECHAT_PACKAGENAME);event.setClassName(Notification.class.getName());CharSequence tickerText = HONGBAO_TEXT_KEY;event.getText().add(tickerText);manager.sendAccessibilityEvent(event);}/** 打開通知欄消息*/@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void openNotify(AccessibilityEvent event) {if(event.getParcelableData() == null || !(event.getParcelableData() instanceof Notification)) {return;}//將微信的通知欄消息打開Notification notification = (Notification) event.getParcelableData();PendingIntent pendingIntent = notification.contentIntent;try {pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}}@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void openHongBao(AccessibilityEvent event) {if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(event.getClassName())) {//點中了紅包,下一步就是去拆紅包ISCOMINQIANGCHB=true;ISCOMINQIANGCHB2=true;checkKey1();} else if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(event.getClassName())) {//拆完紅包后看詳細的紀錄界面LogUtil.info("事件---->com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI");//nonething // if(ISCOMINQIANGCHB){ // ISCOMINQIANGCHB=false; // }if(ISCOMINQIANGCHB2){ISCOMINQIANGCHB3=true;}else{ISCOMINQIANGCHB3=false;}checkKey3();ISCOMINQIANGCHB=true;ISCOMINQIANGCHB2=false;performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);if(getSharedPreferences("config", Context.MODE_PRIVATE).getBoolean("auto", false)){performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);}lock();} else if("com.tencent.mm.ui.LauncherUI".equals(event.getClassName())) { // isInMM=true;//在聊天界面,去點中紅包LogUtil.info("事件---->com.tencent.mm.ui.LauncherUI");checkKey2();}}@SuppressLint("NewApi") @TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void checkKey3() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow為空333");return;}//TODOList<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("元");if(findAccessibilityNodeInfosByText.size()>=0){AccessibilityNodeInfo accessibilityNodeInfo2 = findAccessibilityNodeInfosByText.get(0).getParent();CharSequence money = accessibilityNodeInfo2.getChild(2).getText();CharSequence name = accessibilityNodeInfo2.getChild(0).getText();if(ISCOMINQIANGCHB3){HongBaoInfo info=new HongBaoInfo();info.setStrDateTime(DateFormatUtils.format("yyyy-MM-dd HH:mm:ss", new Date()));info.setStrMoney(money+"");info.setStrName(name+"");info.save();}Toast.makeText(getApplicationContext(), money+":::"+name, 0).show();} // List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/aw8"); // AccessibilityNodeInfo accessibilityNodeInfo = findAccessibilityNodeInfosByViewId.get(0); // CharSequence text = accessibilityNodeInfo.getText(); }private void checkKey1() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow為空11111");return;}for (int i = 0; i < nodeInfo.getChildCount(); i++) {Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());Rect outBounds = new Rect();nodeInfo.getChild(i).getBoundsInScreen(outBounds);int left_dp = px2dip(this, 400);int top_dp = px2dip(this, 1035);int right_dp = px2dip(this, 682);int bottom_dp = px2dip(this, 1320);int left_px = dip2px(this, left_dp);int top_px = dip2px(this, top_dp);int right_px = dip2px(this, right_dp);int bottom_px = dip2px(this, bottom_dp);Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);if(mStandar.contains(outBounds)){Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);break;} // nodeInfo.performAction(action)//[405,1042][675,1312]}//List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("拆紅包");// List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/b5d"); // for(AccessibilityNodeInfo n : list) { // n.performAction(AccessibilityNodeInfo.ACTION_CLICK); // }}private void checkKey2() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow為空222222");return;}List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("領取紅包");if(list.isEmpty()) {list = nodeInfo.findAccessibilityNodeInfosByText(HONGBAO_TEXT_KEY);for(AccessibilityNodeInfo n : list) {LogUtil.info("-->微信紅包:" + n);n.performAction(AccessibilityNodeInfo.ACTION_CLICK);break;}} else {//最新的紅包領起AccessibilityNodeInfo parent = list.get(list.size() - 1).getParent(); // Log.w(TAG, "ISCLICKED::"+ISCLICKED)!ISCLICKED;if(parent != null && !ISCOMINQIANGCHB) {parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);} // for(int i = list.size() - 1; i >= 0; i --) { // AccessibilityNodeInfo parent = list.get(i).getParent(); // Log.i(TAG, "-->領取紅包:" + parent); // if(parent != null && parent.isClickable()) { // parent.performAction(AccessibilityNodeInfo.ACTION_CLICK); // break; // } // } // performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);}}/*** @param info 當前節點* @param matchFlag 需要匹配的文字* @param type 操作的類型*/@SuppressLint("NewApi") public void recycle(AccessibilityNodeInfo info, String matchFlag, int type) {if (info != null) {if (info.getChildCount() == 0) {CharSequence desrc = info.getContentDescription();switch (type) {case ENVELOPE_RETURN://返回if (desrc != null && matchFlag.equals(info.getContentDescription().toString().trim())) {if (info.isCheckable()) {info.performAction(AccessibilityNodeInfo.ACTION_CLICK);} else {performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);}}break;}} else {int size = info.getChildCount();for (int i = 0; i < size; i++) {AccessibilityNodeInfo childInfo = info.getChild(i);if (childInfo != null) {LogUtil.info("index: " + i + " info" + childInfo.getClassName() + " : " + childInfo.getContentDescription()+" : "+info.getText());recycle(childInfo, matchFlag, type);}}}}}@Overridepublic void onDestroy() {super.onDestroy();lock();}/** * 根據手機的分辨率從 dip 的單位 轉成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根據手機的分辨率從 px(像素) 的單位 轉成為 dp */ public static int px2dip(Context context, float pxValue) { // final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / 3 + 0.5f); //3是本人手機的設備密度} }

    AccessibilityService還可以用在智能安裝、虛擬按鍵上都有很多應用,這樣的實踐只是給我們一種解決問題另外的一種思路,問題嘛,總還是要解決的。

    總結

    以上是生活随笔為你收集整理的抢红包插件实现原理浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。