您好,登录后才能下订单哦!
请求超时!
请点击 重新获取二维码现在适配微信版本更加容易了,只需要替换一个Recourse-ID即可
可以知道对方发的是小视频还是语音,并获取秒数。
可以区分聊天信息中的图片或者表情
实现效果:
实时监听当前聊天页面的最新一条消息,效果如图:
实现原理:
同样是利用AccessibilityService辅助服务,关于这个服务类还不了解的同学可以先看下我上一篇关于抢红包的博客,原理都一样:https://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系统无法使用
写在最后:
个人兴趣研究,不建议用在非法途径上!!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
PHP网站源码光明网站推广石岩企业网站改版盐田标王盐田seo优化双龙网页制作平湖关键词按天计费大运网络推广南联关键词排名包年推广广州seo优化松岗网站优化推广坑梓关键词排名平湖网站优化南联网站关键词优化罗湖高端网站设计石岩企业网站制作永湖设计公司网站松岗网站优化双龙百搜词包大浪seo网站推广南澳网站制作设计南澳百度关键词包年推广福田外贸网站建设南联网页设计塘坑标王龙岗百度网站优化排名吉祥网站定制松岗网站优化推广福田建设网站民治seo光明关键词排名包年推广歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运