微信自动回复和自动抢红包实现原理(二):自动回复
閱讀這篇文章前,你需要先了解AccessibilityService,可以先閱讀我上一篇文章
微信自動回復和自動搶紅包實現原理(一):AccessibilityService的介紹和配置
已經了解的朋友可以直接閱讀該文章
完成AccessibilityService的配置后,好像無從下手。先別急,先打印一些log看看吧。把下面的方法放在onAccessibilityEvent()里:
private void printEventLog(AccessibilityEvent event) {Log.i(TAG, "-------------------------------------------------------------");int eventType = event.getEventType(); //事件類型Log.i(TAG, "PackageName:" + event.getPackageName() + ""); // 響應事件的包名Log.i(TAG, "Source Class:" + event.getClassName() + ""); // 事件源的類名Log.i(TAG, "Description:" + event.getContentDescription()+ ""); // 事件源描述Log.i(TAG, "Event Type(int):" + eventType + "");switch (eventType) {case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知欄事件Log.i(TAG, "event type:TYPE_NOTIFICATION_STATE_CHANGED");break;case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED://窗體狀態改變Log.i(TAG, "event type:TYPE_WINDOW_STATE_CHANGED");break;case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED://View獲取到焦點Log.i(TAG, "event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");break;case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:Log.i(TAG, "event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");break;case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:Log.i(TAG, "event type:TYPE_GESTURE_DETECTION_END");break;case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:Log.i(TAG, "event type:TYPE_WINDOW_CONTENT_CHANGED");break;case AccessibilityEvent.TYPE_VIEW_CLICKED:Log.i(TAG, "event type:TYPE_VIEW_CLICKED");break;case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:Log.i(TAG, "event type:TYPE_VIEW_TEXT_CHANGED");break;case AccessibilityEvent.TYPE_VIEW_SCROLLED:Log.i(TAG, "event type:TYPE_VIEW_SCROLLED");break;case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:Log.i(TAG, "event type:TYPE_VIEW_TEXT_SELECTION_CHANGED");break;default:Log.i(TAG, "no listen event");}for (CharSequence txt : event.getText()) {Log.i(TAG, "text:" + txt);}Log.i(TAG, "-------------------------------------------------------------");}向安裝了服務的手機發微信信息,查看打印的log:
非鎖屏(在后臺): ------------------------------------------------------------- packageName:com.tencent.mm source:null source class:android.app.Notification event type(int):64 event type:TYPE_NOTIFICATION_STATE_CHANGED text:[聯系人]: 哦 ------------------------------------------------------------- 非鎖屏(在前臺主界面): ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@8009b539; boundsInParent: Rect(0, 0 - 38, 38); boundsInScreen: Rect(103, 1181 - 141, 1219); packageName: com.tencent.mm; className: android.widget.TextView; text: 1; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null] source class:android.widget.TextView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:null source class:android.app.Notification event type(int):64 event type:TYPE_NOTIFICATION_STATE_CHANGED text:[聯系人]: 呵呵 ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@80043582; boundsInParent: Rect(0, 0 - 38, 38); boundsInScreen: Rect(96, 153 - 134, 191); packageName: com.tencent.mm; className: android.widget.TextView; text: 1; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null] source class:android.widget.TextView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED ------------------------------------------------------------- 非鎖屏(在前臺打開會話人的界面)(沒Notification) ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@8009cbbf; boundsInParent: Rect(0, 0 - 720, 1038); boundsInScreen: Rect(0, 146 - 720, 1184); packageName: com.tencent.mm; className: android.widget.ListView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: true; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: true; actions: [AccessibilityAction: ACTION_FOCUS - null, AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_SCROLL_BACKWARD - null] source class:android.widget.ListView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@801086ca; boundsInParent: Rect(0, 0 - 415, 80); boundsInScreen: Rect(201, 146 - 616, 150); packageName: com.tencent.mm; className: android.widget.TextView; text: 我在敲代碼,稍后回復哈~; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null] source class:android.widget.TextView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@8009cbbf; boundsInParent: Rect(0, 0 - 720, 1038); boundsInScreen: Rect(0, 146 - 720, 1184); packageName: com.tencent.mm; className: android.widget.ListView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: true; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: true; actions: [AccessibilityAction: ACTION_FOCUS - null, AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_SCROLL_BACKWARD - null] source class:android.widget.ListView event type(int):4096 event type:TYPE_VIEW_SCROLLED ------------------------------------------------------------- 非鎖屏(在前臺打開非會話人的界面): ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@800ce011; boundsInParent: Rect(0, 0 - 95, 80); boundsInScreen: Rect(104, 851 - 199, 931); packageName: com.tencent.mm; className: android.widget.TextView; text: [白眼]; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null] source class:android.widget.TextView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:null source class:android.app.Notification event type(int):64 event type:TYPE_NOTIFICATION_STATE_CHANGED text:[聯系人]: 呵呵 ------------------------------------------------------------- ------------------------------------------------------------- packageName:com.tencent.mm source:android.view.accessibility.AccessibilityNodeInfo@8012f5f0; boundsInParent: Rect(0, 0 - 371, 60); boundsInScreen: Rect(174, 591 - 545, 651); packageName: com.tencent.mm; className: android.widget.TextView; text: "?彣????" 撤回了一條消息; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null] source class:android.widget.TextView event type(int):2048 event type:TYPE_WINDOW_CONTENT_CHANGED -------------------------------------------------------------從打印的log和我們平時使用微信應該就知道的了,除了在打開了會話人的聊天界面,否則都會有Notification的,可以以此作為切入點,那么接下來我們的工作就簡單了。步驟如下:
思路很清晰了,難點是如何找到相應的控件。放心,Android也為我們提供了一個類來幫助我們——AccessibilityNodeInfo?,其包含一些控件的信息,可用其找到相應的控件,并做出相應的操作。常用方法:
- CharSequence getClassName () // 獲取控件類名,如按鈕會返回android.widget.Button - CharSequence getText () // 獲取控件的文本,如微信的發送按鈕會返回“發送” - String getViewIdResourceName () // 獲取控件的id代碼注釋很詳細了,就不一一解釋。源碼后面有貼。
/*** 自動回復服務*/ public class AutoReplyService extends AccessibilityService{private static final String TAG = AutoReplyService.class.getSimpleName();private Handler handler = new Handler();private boolean hasNotify = false;/*** 必須重寫的方法,響應各種事件。*/public void onAccessibilityEvent(final AccessibilityEvent event) { int eventType = event.getEventType(); // 事件類型switch (eventType) {case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: // 通知欄事件Log.i(TAG, "TYPE_NOTIFICATION_STATE_CHANGED");if(PhoneController.isLockScreen(this)) { // 鎖屏PhoneController.wakeAndUnlockScreen(this); // 喚醒點亮屏幕}openAppByNotification(event);hasNotify = true;break;default:Log.i(TAG, "DEFAULT");if (hasNotify) { // 如果有通知try {Thread.sleep(1000); // 停1秒, 否則在微信主界面沒進入聊天界面就執行了fillInputBar} catch (InterruptedException e) {e.printStackTrace();}if (fillInputBar("我在敲代碼,稍后回復哈~")) { // 找到輸入框,即EditTextfindAndPerformAction(UI.BUTTON, "發送"); // 點擊發送handler.postDelayed(new Runnable() { // 返回主界面,這里延遲執行,為了有更好的交互public void run() {performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); // 返回}}, 1500);}hasNotify = false;}break;}}public void onInterrupt() {}/*** 查找UI控件并點擊* @param widget 控件完整名稱, 如android.widget.Button, android.widget.TextView* @param text 控件文本*/private void findAndPerformAction(String widget, String text) {// 取得當前激活窗體的根節點if (getRootInActiveWindow() == null) {return;}// 通過文本找到當前的節點List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByText(text);if(nodes != null) {for (AccessibilityNodeInfo node : nodes) {if (node.getClassName().equals(widget) && node.isEnabled()) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK); // 執行點擊break;}}}}/*** 打開微信* @param event 事件*/private void openAppByNotification(AccessibilityEvent event) {if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {Notification notification = (Notification) event.getParcelableData();try {PendingIntent pendingIntent = notification.contentIntent;pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}}}/*** 填充輸入框*/private boolean fillInputBar(String reply) {AccessibilityNodeInfo rootNode = getRootInActiveWindow();if (rootNode != null) {return findInputBar(rootNode, reply);}return false;}/*** 查找EditText控件* @param rootNode 根結點* @param reply 回復內容* @return 找到返回true, 否則返回false*/private boolean findInputBar(AccessibilityNodeInfo rootNode, String reply) {int count = rootNode.getChildCount();for (int i = 0; i < count; i++) {AccessibilityNodeInfo node = rootNode.getChild(i);if (UI.EDITTEXT.equals(node.getClassName())) { // 找到輸入框并輸入文本setText(node, reply);return true;}if (findInputBar(node, reply)) { // 遞歸查找return true;}}return false;}/*** 設置文本*/private void setText(AccessibilityNodeInfo node, String reply) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {Bundle args = new Bundle();args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,reply);node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);} else {ClipData data = ClipData.newPlainText("reply", reply);ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);clipboardManager.setPrimaryClip(data);node.performAction(AccessibilityNodeInfo.ACTION_FOCUS); // 獲取焦點node.performAction(AccessibilityNodeInfo.ACTION_PASTE); // 執行粘貼}} }這里我沒有處理打開了會話人聊天界面的情況,我覺得你都打開了會話人的聊天界面,就證明你想與他聊天,也就不需要自動回復了。當然,如果你遍要(不帶你這樣敷衍朋友的),只要加點簡單邏輯就可以實現了~到這里微信自動回復功能就完成了,怎樣,是不是很簡單!感興趣的朋友可以繼續看我下一篇文章:
微信自動回復和自動搶紅包實現原理(三):自動搶紅包
源碼下載
原文地址: http://www.jianshu.com/p/5b4a4a5aca7e
總結
以上是生活随笔為你收集整理的微信自动回复和自动抢红包实现原理(二):自动回复的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信自动回复和自动抢红包实现原理(一):
- 下一篇: 微信自动回复和自动抢红包实现原理(三):