編輯:關於Android編程
現在適配微信版本更加容易了,只需要替換一個Recourse-ID即可
可以知道對方發的是小視頻還是語音,並獲取秒數。
可以區分聊天信息中的圖片或者表情
實現效果:
實時監聽當前聊天頁面的最新一條消息,效果如圖:
實現原理:
同樣是利用AccessibilityService輔助服務,關於這個服務類還不了解的同學可以先看下我上一篇關於搶紅包的博客,原理都一樣:http://www.jb51.net/article/104507.htm
1.首先我們先來看一下微信聊天界面的布局,查看方法:
AndroidStudio--Tools--Android--Android Device Monitor,點擊:
2.如圖我們可以看到,其實每一條微信聊天記錄都是一個RelativeLayout:
3.再往下看,我們又可以發現,其實每一個RelativeLayout下面,又包含了一個TextView,還有一個LinearLayout
TextView就是聊天的時間
LinearLayout下則包含了我們所需要的聊天對象以及聊天信息,除了文字聊天,語音,圖片等的聊天信息都會在這個LinearLayout下,看圖2
4.這裡聊天對象比較容易獲得,我們先放在前面講,如上圖我們可以看到有一個ImageView的描述內容裡面包含著我們的聊天對象,可能後面還會有很多ImageView的參雜,將它與其他ImageView區分還有很重要兩點,一是它是isClickable,二是它存在描述內容,並且描述內容是還包含有“頭像”字眼。
綜合過濾條件: "android.widget.ImageView"+"isClickable()"+"node.getContentDescription().toString().contains("頭像")",代碼如下:
/**
* 遍歷所有控件,找到頭像Imagview,裡面有對聯系人的描述
*/ private void GetChatName(AccessibilityNodeInfo node) { for (int i = 0; i < node.getChildCount(); i++) { AccessibilityNodeInfo node1 = node.getChild(i); if ("android.widget.ImageView".equals(node1.getClassName()) && node1.isClickable()) { //獲取聊天對象,這裡兩個if是為了確定找到的這個ImageView是頭像的 if (!TextUtils.isEmpty(node1.getContentDescription())) { ChatName = node1.getContentDescription().toString(); if (ChatName.contains("頭像")) { ChatName = ChatName.replace("頭像", ""); } } } GetChatName(node1); } }
5.這裡我們暫時把微信的聊天信息分為5種:
a.單純的文字聊天信息:
其實從上面的右邊圖就可以看到,他就是一個TextView而已,如果你有去打印看看的話,你會發現他的parent父布局其實是一個RelativeLayout,後面同樣可能會有其他的TeView干擾,例如我推薦了個名片或者發了個紅包等,所以文字聊天TeView區分其他TextView的還有一個很重的過濾條件,就是它是可以長按的(isLongClickable()),這些屬性都可以在Android Device Monitor中查看到。
綜合過濾條件:"android.widget.TextView"+“android.widget.RelativeLayout”+“isLongClickable()”
b.發了一段語音聊天信息:
我們這裡並沒有辦法獲取到語音內容,只能獲取語音的秒數,獲取方法跟上面的一模一樣,只不過這裡它不能長按。我們知道語音的秒數格式都是:數字+雙引號("),如60",所以我們只要判斷取得的TextView內容是不是符合這種格式就行了,就能判斷它是語音秒數。
綜合過濾條件:"android.widget.TextView"+“android.widget.RelativeLayout”+“符合秒數格式”
c.發了一個表情:
這裡的表情指的是收藏的或者自己下載的那些表情,不是指Emoji那些,他其實就是一個ImagView,父布局是一個LinearLayout。
綜合過濾條件:"android.widget.ImageView"+"android.widget.LinearLayout"
d.發了一張圖片:
這裡目前只能做到監聽到安裝服務的這一端發過去的圖片,不能監聽到對面發過來的啧啧,其實也是一個ImageView,父布局是FrameLayout,而且還有很重要一點,該節點存在描述內容字眼:"圖片"。
綜合過濾條件:"android.widget.ImageView"+"android.widget.FrameLayout"+"node.getContentDescription().toString().contains("圖片")"
e.發了一段小視頻:
同樣我們無法知道視頻的內容,這裡只是單純的獲取視頻的秒數,和語音類似,但是獲取過濾方法不同,其實小視頻秒數也就是個TextView,並且它的父布局是FrameLayout,我們知道視頻的秒數都是符合:00:00這種格式的,所以這個也是個很重要的過濾條件。
綜合過濾條件:"android.widget.TextView"+“android.widget.FrameLayout”+“符合 00:00格式”
4.分析完後,我們思路就有了:
a.首先我們先取得根布局的節點,然後通過遍歷獲取到每個RelativeLayout下的LinearLayout,因為該LinearLayout存在resource-id(com.tencent.mm:id/p,微信版本6.5.4),所以我們可以很容易可以獲取到符合該ID的所有LinearLayout,然後我們取出最後一個LinearLayout,這個也就是裝載著我們最新的那條消息啦。
b.然後我們再在該LinearLayout下遍歷它的所有控件,通過上面所講的各種過濾條件,判斷發的是什麼類型的消息並取出我們所需要的即可。
注:關於resource-id直接在上一步的查看布局下可看到,因為resource-id隨著版本的迭代可能也會發生改變,Demo中那個LinearLayout的resource-id是基於微信6.5.4滴,如果以後有版本更新的話我們直接修改代碼中的那個ID就行啦。
獲取聊天信息核心代碼:
代碼不多,也加了注釋,直接看代碼即可:
/** * 遍歷所有控件:這裡分四種情況 * 文字聊天: 一個TextView,並且他的父布局是android.widget.RelativeLayout * 語音的秒數: 一個TextView,並且他的父布局是android.widget.RelativeLayout,但是他的格式是0"的格式,所以可以通過這個來區分 * 圖片:一個ImageView,並且他的父布局是android.widget.FrameLayout,描述中包含“圖片”字樣(發過去的圖片),發回來的圖片現在還無法監聽 * 表情:也是一個ImageView,並且他的父布局是android.widget.LinearLayout * 小視頻的秒數:一個TextView,並且他的父布局是android.widget.FrameLayout,但是他的格式是00:00"的格式,所以可以通過這個來區分 * * @param node */ public void GetChatRecord(AccessibilityNodeInfo node) { for (int i = 0; i < node.getChildCount(); i++) { AccessibilityNodeInfo nodeChild = node.getChild(i); //聊天內容是:文字聊天(包含語音秒數) if ("android.widget.TextView".equals(nodeChild.getClassName()) && "android.widget.RelativeLayout".equals(nodeChild.getParent().getClassName().toString())) { if (!TextUtils.isEmpty(nodeChild.getText())) { String RecordText = nodeChild.getText().toString(); //這裡加個if是為了防止多次觸發TYPE_VIEW_SCROLLED而打印重復的信息 if (!RecordText.equals(ChatRecord)) { ChatRecord = RecordText; //判斷是語音秒數還是正常的文字聊天,語音的話秒數格式為5" if (ChatRecord.contains("\"")) { Toast.makeText(this, ChatName + "發了一條" + ChatRecord + "的語音", Toast.LENGTH_SHORT).show(); Log.e("WeChatLog",ChatName + "發了一條" + ChatRecord + "的語音"); } else { //這裡在加多一層過濾條件,確保得到的是聊天信息,因為有可能是其他TextView的干擾,例如名片等 if (nodeChild.isLongClickable()) { Toast.makeText(this, ChatName + ":" + ChatRecord, Toast.LENGTH_SHORT).show(); Log.e("WeChatLog",ChatName + ":" + ChatRecord); } } return; } } } //聊天內容是:表情 if ("android.widget.ImageView".equals(nodeChild.getClassName()) && "android.widget.LinearLayout".equals(nodeChild.getParent().getClassName().toString())) { Toast.makeText(this, ChatName+"發的是表情", Toast.LENGTH_SHORT).show(); Log.e("WeChatLog",ChatName+"發的是表情"); return; } //聊天內容是:圖片 if ("android.widget.ImageView".equals(nodeChild.getClassName())) { //安裝軟件的這一方發的圖片(另一方發的暫時沒實現) if("android.widget.FrameLayout".equals(nodeChild.getParent().getClassName().toString())){ if(!TextUtils.isEmpty(nodeChild.getContentDescription())){ if(nodeChild.getContentDescription().toString().contains("圖片")){ Toast.makeText(this, ChatName+"發的是圖片", Toast.LENGTH_SHORT).show(); Log.e("WeChatLog",ChatName+"發的是圖片"); } } } } //聊天內容是:小視頻秒數,格式為00:00 if ("android.widget.TextView".equals(nodeChild.getClassName()) && "android.widget.FrameLayout".equals(nodeChild.getParent().getClassName().toString())) { if (!TextUtils.isEmpty(nodeChild.getText())) { String second = nodeChild.getText().toString().replace(":", ""); //正則表達式,確定是不是純數字,並且做重復判斷 if (second.matches("[0-9]+") && !second.equals(VideoSecond)) { VideoSecond = second; Toast.makeText(this, ChatName + "發了一段" + nodeChild.getText().toString() + "的小視頻", Toast.LENGTH_SHORT).show(); Log.e("WeChatLog","發了一段" + nodeChild.getText().toString() + "的小視頻"); } } } GetChatRecord(nodeChild); } }
使用方法:
設置-輔助功能-無障礙-點擊WeChatLog開啟即可(或者在設置中查找輔助功能等)
已知Bug:
沒安裝服務的另一方發的圖片暫時無法監聽到,後面改善
圖片和表情沒做重復信息過濾處理,所以如果觸發了TYPE_VIEW_SCROLLED並且最新那條是這兩個的話會出現重復。
華為7.0系統無法使用
寫在最後:
個人興趣研究,不建議用在非法途徑上!!
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
上一篇博客介紹了AS的一些常用設置方法,當工具調教妥當後,自然就要開始項目的開發啦。從零開始新建一個項目,這個簡單,不必多說,這篇博客會分享我從舊平台eclipse導入項
話不多說,我們先來看看效果:Hi前輩搜索預覽這一張是《Hi前輩》的搜索預覽圖,你可以在這裡下載這個APP查看更多效果:http://www.wandoujia.com/a
Gallery與Spinner有共同父類:AbsPinner,說明Gallery與Spinner都是一個列表框。它們之間的區別在於Spinner顯示的是一個垂直的列表選擇
第1節 選擇Arduino開發板1.1 Arduino是什麼對Arduino,官方有一堆解釋。作為一個軟件程序猿,在我眼裡,Arduino是學習“可怕硬件&r