国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android幾行代碼實現(xiàn)監(jiān)聽微信聊天示例

2019-12-12 03:45:32
字體:
來源:轉載
供稿:網(wǎng)友

現(xiàn)在適配微信版本更加容易了,只需要替換一個Recourse-ID即可

可以知道對方發(fā)的是小視頻還是語音,并獲取秒數(shù)。

可以區(qū)分聊天信息中的圖片或者表情

實現(xiàn)效果:

實時監(jiān)聽當前聊天頁面的最新一條消息,效果如圖:

 

                      

實現(xiàn)原理:

同樣是利用AccessibilityService輔助服務,關于這個服務類還不了解的同學可以先看下我上一篇關于搶紅包的博客,原理都一樣://m.survivalescaperooms.com/article/104507.htm

1.首先我們先來看一下微信聊天界面的布局,查看方法:

AndroidStudio--Tools--Android--Android Device Monitor,點擊:

     

 2.如圖我們可以看到,其實每一條微信聊天記錄都是一個RelativeLayout:

 3.再往下看,我們又可以發(fā)現(xiàn),其實每一個RelativeLayout下面,又包含了一個TextView,還有一個LinearLayout

TextView就是聊天的時間

LinearLayout下則包含了我們所需要的聊天對象以及聊天信息,除了文字聊天,語音,圖片等的聊天信息都會在這個LinearLayout下,看圖2

 4.這里聊天對象比較容易獲得,我們先放在前面講,如上圖我們可以看到有一個ImageView的描述內(nèi)容里面包含著我們的聊天對象,可能后面還會有很多ImageView的參雜,將它與其他ImageView區(qū)分還有很重要兩點,一是它是isClickable,二是它存在描述內(nèi)容,并且描述內(nèi)容是還包含有“頭像”字眼。

綜合過濾條件: "android.widget.ImageView"+"isClickable()"+"node.getContentDescription().toString().contains("頭像")",代碼如下:

    /**
     * 遍歷所有控件,找到頭像Imagview,里面有對聯(lián)系人的描述
     */ 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而已,如果你有去打印看看的話,你會發(fā)現(xiàn)他的parent父布局其實是一個RelativeLayout,后面同樣可能會有其他的TeView干擾,例如我推薦了個名片或者發(fā)了個紅包等,所以文字聊天TeView區(qū)分其他TextView的還有一個很重的過濾條件,就是它是可以長按的(isLongClickable()),這些屬性都可以在Android Device Monitor中查看到。

綜合過濾條件:"android.widget.TextView"+“android.widget.RelativeLayout”+“isLongClickable()”

b.發(fā)了一段語音聊天信息:

我們這里并沒有辦法獲取到語音內(nèi)容,只能獲取語音的秒數(shù),獲取方法跟上面的一模一樣,只不過這里它不能長按。我們知道語音的秒數(shù)格式都是:數(shù)字+雙引號("),如60",所以我們只要判斷取得的TextView內(nèi)容是不是符合這種格式就行了,就能判斷它是語音秒數(shù)。

綜合過濾條件:"android.widget.TextView"+“android.widget.RelativeLayout”+“符合秒數(shù)格式”

c.發(fā)了一個表情:

這里的表情指的是收藏的或者自己下載的那些表情,不是指Emoji那些,他其實就是一個ImagView,父布局是一個LinearLayout。

綜合過濾條件:"android.widget.ImageView"+"android.widget.LinearLayout"

d.發(fā)了一張圖片:

這里目前只能做到監(jiān)聽到安裝服務的這一端發(fā)過去的圖片,不能監(jiān)聽到對面發(fā)過來的嘖嘖,其實也是一個ImageView,父布局是FrameLayout,而且還有很重要一點,該節(jié)點存在描述內(nèi)容字眼:"圖片"。

綜合過濾條件:"android.widget.ImageView"+"android.widget.FrameLayout"+"node.getContentDescription().toString().contains("圖片")"

e.發(fā)了一段小視頻:

同樣我們無法知道視頻的內(nèi)容,這里只是單純的獲取視頻的秒數(shù),和語音類似,但是獲取過濾方法不同,其實小視頻秒數(shù)也就是個TextView,并且它的父布局是FrameLayout,我們知道視頻的秒數(shù)都是符合:00:00這種格式的,所以這個也是個很重要的過濾條件。

綜合過濾條件:"android.widget.TextView"+“android.widget.FrameLayout”+“符合 00:00格式”

 4.分析完后,我們思路就有了:

a.首先我們先取得根布局的節(jié)點,然后通過遍歷獲取到每個RelativeLayout下的LinearLayout,因為該LinearLayout存在resource-id(com.tencent.mm:id/p,微信版本6.5.4),所以我們可以很容易可以獲取到符合該ID的所有LinearLayout,然后我們?nèi)〕鲎詈笠粋€LinearLayout,這個也就是裝載著我們最新的那條消息啦。

b.然后我們再在該LinearLayout下遍歷它的所有控件,通過上面所講的各種過濾條件,判斷發(fā)的是什么類型的消息并取出我們所需要的即可。

注:關于resource-id直接在上一步的查看布局下可看到,因為resource-id隨著版本的迭代可能也會發(fā)生改變,Demo中那個LinearLayout的resource-id是基于微信6.5.4滴,如果以后有版本更新的話我們直接修改代碼中的那個ID就行啦。

獲取聊天信息核心代碼:

代碼不多,也加了注釋,直接看代碼即可:

 

/**   * 遍歷所有控件:這里分四種情況   * 文字聊天: 一個TextView,并且他的父布局是android.widget.RelativeLayout   * 語音的秒數(shù): 一個TextView,并且他的父布局是android.widget.RelativeLayout,但是他的格式是0"的格式,所以可以通過這個來區(qū)分   * 圖片:一個ImageView,并且他的父布局是android.widget.FrameLayout,描述中包含“圖片”字樣(發(fā)過去的圖片),發(fā)回來的圖片現(xiàn)在還無法監(jiān)聽   * 表情:也是一個ImageView,并且他的父布局是android.widget.LinearLayout   * 小視頻的秒數(shù):一個TextView,并且他的父布局是android.widget.FrameLayout,但是他的格式是00:00"的格式,所以可以通過這個來區(qū)分   *   * @param node   */  public void GetChatRecord(AccessibilityNodeInfo node) {    for (int i = 0; i < node.getChildCount(); i++) {      AccessibilityNodeInfo nodeChild = node.getChild(i);      //聊天內(nèi)容是:文字聊天(包含語音秒數(shù))      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是為了防止多次觸發(fā)TYPE_VIEW_SCROLLED而打印重復的信息          if (!RecordText.equals(ChatRecord)) {            ChatRecord = RecordText;            //判斷是語音秒數(shù)還是正常的文字聊天,語音的話秒數(shù)格式為5"            if (ChatRecord.contains("/"")) {              Toast.makeText(this, ChatName + "發(fā)了一條" + ChatRecord + "的語音", Toast.LENGTH_SHORT).show();              Log.e("WeChatLog",ChatName + "發(fā)了一條" + ChatRecord + "的語音");            } else {              //這里在加多一層過濾條件,確保得到的是聊天信息,因為有可能是其他TextView的干擾,例如名片等              if (nodeChild.isLongClickable()) {                Toast.makeText(this, ChatName + ":" + ChatRecord, Toast.LENGTH_SHORT).show();                Log.e("WeChatLog",ChatName + ":" + ChatRecord);              }            }            return;          }        }      }      //聊天內(nèi)容是:表情      if ("android.widget.ImageView".equals(nodeChild.getClassName()) && "android.widget.LinearLayout".equals(nodeChild.getParent().getClassName().toString())) {        Toast.makeText(this, ChatName+"發(fā)的是表情", Toast.LENGTH_SHORT).show();        Log.e("WeChatLog",ChatName+"發(fā)的是表情");        return;      }      //聊天內(nèi)容是:圖片      if ("android.widget.ImageView".equals(nodeChild.getClassName())) {        //安裝軟件的這一方發(fā)的圖片(另一方發(fā)的暫時沒實現(xiàn))        if("android.widget.FrameLayout".equals(nodeChild.getParent().getClassName().toString())){          if(!TextUtils.isEmpty(nodeChild.getContentDescription())){            if(nodeChild.getContentDescription().toString().contains("圖片")){              Toast.makeText(this, ChatName+"發(fā)的是圖片", Toast.LENGTH_SHORT).show();              Log.e("WeChatLog",ChatName+"發(fā)的是圖片");            }          }        }      }      //聊天內(nèi)容是:小視頻秒數(shù),格式為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(":", "");          //正則表達式,確定是不是純數(shù)字,并且做重復判斷          if (second.matches("[0-9]+") && !second.equals(VideoSecond)) {            VideoSecond = second;            Toast.makeText(this, ChatName + "發(fā)了一段" + nodeChild.getText().toString() + "的小視頻", Toast.LENGTH_SHORT).show();            Log.e("WeChatLog","發(fā)了一段" + nodeChild.getText().toString() + "的小視頻");          }        }      }      GetChatRecord(nodeChild);    }  }

使用方法:

設置-輔助功能-無障礙-點擊WeChatLog開啟即可(或者在設置中查找輔助功能等)

 已知Bug:

沒安裝服務的另一方發(fā)的圖片暫時無法監(jiān)聽到,后面改善

圖片和表情沒做重復信息過濾處理,所以如果觸發(fā)了TYPE_VIEW_SCROLLED并且最新那條是這兩個的話會出現(xiàn)重復。

華為7.0系統(tǒng)無法使用

 寫在最后:

個人興趣研究,不建議用在非法途徑上!!

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 长阳| 岳普湖县| 西充县| 梅河口市| 巧家县| 延庆县| 富裕县| 阿瓦提县| 凤山县| 新乡市| 平昌县| 青海省| 政和县| 吉林省| 黄大仙区| 张家口市| 镶黄旗| 隆尧县| 丽江市| 怀来县| 淄博市| 弋阳县| 萍乡市| 东兴市| 南投县| 新河县| 四子王旗| 左云县| 镇江市| 抚松县| 四川省| 沁阳市| 中方县| 抚宁县| 农安县| 皮山县| 庆元县| 东莞市| 武功县| 固原市| 湟中县|