實現效果:
實時監聽當前聊天頁面的最新一條消息,如圖:
實現原理:
同樣是利用AccessibilityService輔助服務,關於這個服務類還不了解的同學可以先看下我上一篇關於搶紅包的博客,原理都一樣:
http://www.cnblogs.com/cxk1995/p/6363574.html
1.首先我們先來看一下微信聊天界面的布局,查看方法:
AndroidStudio--Tools--Android--Android Device Monitor,點擊:
2.如圖我們可以看到,其實每一條微信聊天記錄都是一個RelativeLayout:
3.再往下看,我們又可以發現,其實每一個RelativeLayout下面,又包含了一個TextView,還有一個LinearLayout
TextView就是聊天的時間
LinearLayout下則包含了我們所需要的聊天對象以及聊天信息,目前我們只需要這個就行了。
4.分析完后,我們思路就有了:
首先遍歷獲取每個RelativeLayout下的LinearLayout,因為該LinearLayout存在resource-id(com.tencent.mm:id/o),所以我們可以很容易可以獲取到,然后我們再在LinearLayout中查找含有聊天對象(resource-id:com.tencent.mm:id/i_)以及聊天內容(resource-id:com.tencent.mm:id/ib)。
注:關於resource-id直接在上一步的查看布局下發可看到,因為resource-id隨着版本的迭代可能會發生改變,所以也導致了一些不穩定因素。
核心代碼
代碼不多,也加了注釋,直接看代碼即可:
package com.cxk.wechatlog; import android.accessibilityservice.AccessibilityService; import android.content.Intent; import android.text.TextUtils; import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Toast; import java.util.List; /** * Created by cxk on 2017/2/4. * email:471497226@qq.com * <p> * 獲取即時微信聊天記錄服務類 */ public class WeChatLogService extends AccessibilityService { /** * 聊天對象 */ private String ChatName; /** * 聊天最新一條記錄 */ private String ChatRecord = "test"; @Override public void onAccessibilityEvent(AccessibilityEvent event) { int eventType = event.getEventType(); switch (eventType) { //每次在聊天界面中有新消息到來時都出觸發該事件 case AccessibilityEvent.TYPE_VIEW_SCROLLED: //獲取當前聊天頁面的根布局 AccessibilityNodeInfo rootNode = getRootInActiveWindow(); //獲取聊天信息 getWeChatLog(rootNode); break; } } /** * 遍歷 * * @param rootNode */ private void getWeChatLog(AccessibilityNodeInfo rootNode) { if (rootNode != null) { //獲取所有聊天的線性布局 List<AccessibilityNodeInfo> listChatRecord = rootNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/o"); if(listChatRecord.size()==0){ return; } //獲取最后一行聊天的線性布局(即是最新的那條消息) AccessibilityNodeInfo finalNode = listChatRecord.get(listChatRecord.size() - 1); //獲取聊天對象list(其實只有size為1) List<AccessibilityNodeInfo> imageName = finalNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/i_"); //獲取聊天信息list(其實只有size為1) List<AccessibilityNodeInfo> record = finalNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ib"); if (imageName.size() != 0) { if (record.size() == 0) { //判斷當前這條消息是不是和上一條一樣,防止重復 if (!ChatRecord.equals("對方發的是圖片或者表情")) { //獲取聊天對象 ChatName = imageName.get(0).getContentDescription().toString().replace("頭像", ""); //獲取聊天信息 ChatRecord = "對方發的是圖片或者表情"; Log.e("AAAA", ChatName + ":" + "對方發的是圖片或者表情"); Toast.makeText(this, ChatName + ":" + ChatRecord, Toast.LENGTH_SHORT).show(); } } else { //判斷當前這條消息是不是和上一條一樣,防止重復 if (!ChatRecord.equals(record.get(0).getText().toString())) { //獲取聊天對象 ChatName = imageName.get(0).getContentDescription().toString().replace("頭像", ""); //獲取聊天信息 ChatRecord = record.get(0).getText().toString(); Log.e("AAAA", ChatName + ":" + ChatRecord); Toast.makeText(this, ChatName + ":" + ChatRecord, Toast.LENGTH_SHORT).show(); } } } } } /** * 必須重寫的方法:系統要中斷此service返回的響應時會調用。在整個生命周期會被調用多次。 */ @Override public void onInterrupt() { Toast.makeText(this, "我快被終結了啊-----", Toast.LENGTH_SHORT).show(); } /** * 服務開始連接 */ @Override protected void onServiceConnected() { Toast.makeText(this, "服務已開啟", Toast.LENGTH_SHORT).show(); super.onServiceConnected(); } /** * 服務斷開 * * @param intent * @return */ @Override public boolean onUnbind(Intent intent) { Toast.makeText(this, "服務已被關閉", Toast.LENGTH_SHORT).show(); return super.onUnbind(intent); } }
使用方法:
設置-輔助功能-無障礙-點擊WeChatLog開啟即可