实现效果:
实时监听当前聊天页面的最新一条消息,如图:
实现原理:
同样是利用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开启即可