Android几行代码实现监听微信聊天

时间:2022-09-04 11:38:00

原创作品,转载请注明出处,尊重别人的劳动果实。

2017.2.7更新:

*现在适配微信版本更加容易了,只需要替换一个Recourse-ID即可

*可以知道对方发的是小视频还是语音,并获取秒数。

*可以区分聊天信息中的图片或者表情

实现效果:

实时监听当前聊天页面的最新一条消息,效果如图:

Android几行代码实现监听微信聊天                       Android几行代码实现监听微信聊天

实现原理:

同样是利用AccessibilityService辅助服务,关于这个服务类还不了解的同学可以先看下我上一篇关于抢红包的博客,原理都一样:

http://www.cnblogs.com/cxk1995/p/6363574.html

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

AndroidStudio--Tools--Android--Android Device Monitor,点击:

Android几行代码实现监听微信聊天

2.如图我们可以看到,其实每一条微信聊天记录都是一个RelativeLayout:

Android几行代码实现监听微信聊天

3.再往下看,我们又可以发现,其实每一个RelativeLayout下面,又包含了一个TextView,还有一个LinearLayout

TextView就是聊天的时间

LinearLayout下则包含了我们所需要的聊天对象以及聊天信息,除了文字聊天,语音,图片等的聊天信息都会在这个LinearLayout下,看图2

Android几行代码实现监听微信聊天Android几行代码实现监听微信聊天

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系统无法使用

写在最后:

个人兴趣研究,不建议用在非法途径上!!

上面是大部分的核心代码,不是完整的Demo,其实也就一个服务类而已,想要Demo的留言我发给你。

欢迎一起讨论学习:471497226@qq.com

Android几行代码实现监听微信聊天的更多相关文章

  1. Android几行代码实现实时监听微信聊天

    实现效果: 实时监听当前聊天页面的最新一条消息,如图:            实现原理: 同样是利用AccessibilityService辅助服务,关于这个服务类还不了解的同学可以先看下我上一篇关于 ...

  2. 拉仇恨!webhook &plus; 企业微信给同事做了个代码提交监听工具

    本文案例收录在 https://github.com/chengxy-nds/Springboot-Notebook 大家好,我是小富~ 最近接个任务,用webhook做了个代码提交监听功能,就是有人 ...

  3. 微信浏览器返回刷新,监听微信浏览器返回事件,网页防复制,移动端禁止图片长按和vivo手机点击img标签放大图片

    以下代码都经过iphone7,华为MT7 ,谷歌浏览器,微信开发者工具,PC端微信验证.如有bug,还请在评论区留言. demo链接:https://pan.baidu.com/s/1c35mbjM ...

  4. android BroadcastReceiver ACTION&lowbar;TIME&lowbar;TICK 系统时间监听不到

    android BroadcastReceiver ACTION_TIME_TICK 系统时间监听不到 今天做android上的消息推送,启动了一个独立service,然后在里面监听系统的ACTION ...

  5. 监听微信端,手机端,ios端的浏览器返回事件,pc端关闭事件

    直接上代码了,可以监听微信端,手机端,iOS端的浏览器返回事件,关闭事件不支持 当进入该页面,我们就给这个history压入一个本地的连接.当点击返回.后退及上一页的操作时,就进行监听,在监听代码中实 ...

  6. android的Home键的监听封装工具类&lpar;一&rpar;

    android的Home键的监听封装: package com.gzcivil.utils; import android.content.BroadcastReceiver; import andr ...

  7. 《Android第一行代码》笔记

    学习Android开发差点儿相同有两年时间了.期间也做了大大小小的一些项目.近来抽出闲暇想把Android基础强化一下,之前在网上看到了郭霖郭大神的几篇博客.从中受益不少.于是花了近一周时间看完了郭神 ...

  8. 20 行代码极速为 App 加上聊天功能

    现在很多 App 都需要集成 IM 功能,今天就为大家分享一下集成 IM 基本功能的步骤.本文内容以 JMessage 为例.极光 IM ( JMessage ) = 极光推送 ( JPush ) + ...

  9. Android之自定义AlertDialog无法监听控件

    参考:http://www.cnblogs.com/511mr/archive/2011/10/21/2220253.html 要做一个自定义的弹出框,以前都是用一个Activity来实现,总觉得不是 ...

随机推荐

  1. Leetcode&colon; Longest Substring with At Most K Distinct Characters &amp&semi;&amp&semi; Summary&colon; Window做法两种思路总结

    Given a string, find the length of the longest substring T that contains at most k distinct characte ...

  2. oracle 学习笔记 复制表结构

    1.复制表结构以及数据 create table d_table_name as select * from s_table_name;  ---注意并不会创建索引 2.只复制表结构 create t ...

  3. JSLint是一个JavaScript的代码质量工具

    JSLint是一个JavaScript的代码质量工具 可能都或多或少的知道JSLint是一个JavaScript的代码质量工具,一个JavaScript语法检查器和校验器,它能分析JavaScript ...

  4. unison&plus;inotify的Web目录同步方案

    1.在Linux下做WEB目录文件同步 一般有如下几种方式: ----------------------------------------------- 1)       nfs实现web数据共享 ...

  5. Unity3D-RayMarch-几何图元0

    效果图: 将下面的shader代码对应的Material拖给一个面片,即可看到效果. shader代码: // Upgrade NOTE: replaced '_Object2World' with ...

  6. Windows防火墙配置(允许某个网段和部分IP访问某个端口)

    1.win+R 2.gpedit.msc 3.计算机配置+Windows设置+安全设置+IP安全策略,在本地计算机 4.创建IP安全策略 5.配置IP筛选器列表.筛选器操作 6.分配 192.168. ...

  7. Django的Session存储Redis环境配置

    第一步:在项目目录下的settings.py中MIDDLEWARE中加上中间件: # session中间件Django项目默认启用Session 'django.contrib.sessions.mi ...

  8. 群里提到的IE设置问题 ---B&sol;S 下页面刷新问题

    这里面四个选项的含义 下面是每个选项的作用和意义: 1. “每次访问此页时检查”选项表示浏览器每次访问一个页面时,不管浏览器是否缓存过此页面,都要向服务器发出访问请求.这种设置的优点是实时性很强,肯定 ...

  9. Qt5&lowbar;加载DLL

    1.QLibrary 加载普通 DLL //写清楚库的路径,如果放在当前工程的目录下,路径为./Oracle.so QLibrary *libOCI = new QLibrary("F:\\ ...

  10. python笔记8-多线程threading之封装式

    执行函数 1.先写一个执行函数,用来实现做某件事情,不同的人吃火锅用一个参数people代替. # coding=utf-8 import threading import time def chiH ...