之前用过基于web版微信的机器人,但是有几个缺点:比如新号不能登录,经常被封等问题。app版的微信机器人原理是模拟人工点击,能避免web版的很多问题,缺点是速度比较慢,成本比较高。目前实现的功能是自动回复消息、主动发送消息、同意好友申请。
先上个图感受一下:
1、准备工作:老版本微信,我用的是6.5.10,之所以不用最新版是因为聊天界面的文本区老版本是textview,新版本改成了view,导致无法拿到消息内容。
如果想输入汉字的话,还要准备一个特殊的输入法:ADBKeyBoard,普通的输入法是不支持的,安装包ADBKeyBoard.apk放在了项目里,在文章最后。
获取控件id我用的是monitor,在studio工具栏的后面,打开并连接手机成功之后,点击获取当前手机屏幕,选中你要的控件,在Node Detail里就可以看到它的相关信息了。
已获取root权限的手机一部
2、开发:主要的技术点来源于github上大神做的抢红包外挂AccessibilityService和Shell命令,前者用于定位到具体的页面与控件还有模拟操作,后者主要用于模拟操作。AccessibilityService在做模拟操作有一定的缺陷,比如没有id的控件是无法点击的,点击次数不好控制,Shell命令则可以完美的实现这两点。废话不多说了,上代码:
//收到消息,发送
private boolean isSend = false;
//是否在输入
private boolean isInputEnter = false;
//是否在设置备注
private boolean isSetBz = false;
//加好友
private boolean isAdd = false;
//第一次发消息
private boolean isFirst = false;
//第一次发送
private boolean isFirstSend = false;
//是否主动发送消息
private boolean isPushMsg = false;
//是否输入了昵称
private boolean isPushCode = false;
private boolean isBack = false;
//微信号
private String wxNoStr;
//最新一条微信消息
private String wxMsgStr;
private boolean isAddFriendCheck = false;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (BuildConfig.DEBUG) {
//Log.e(TAG, "事件--->" + event);
}
String pkn = String.valueOf(event.getPackageName());
if ("com.tencent.mm".equals(pkn)) {
final AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo == null) {
Log.w(TAG, "rootWindow为空");
return;
}
if (isBack) {
String homeWx = "com.tencent.mm:id/bw6";
AccessibilityNodeInfo targetHomeWx = AccessibilityHelper.findNodeInfosById(nodeInfo, homeWx);
if (targetHomeWx == null || targetHomeWx.getText() == null ||
!"微信".equals(targetHomeWx.getText().toString().trim())) {
execShellCmd(String.format("input tap %s %s", getRandom(5, 80), getRandom(80, 130)));
return;
} else {
AccessibilityHelper.performClick(targetHomeWx);
isBack = false;
}
}
String dialogTitleId = "com.tencent.mm:id/bvo";
AccessibilityNodeInfo targetTitle = AccessibilityHelper.findNodeInfosById(nodeInfo, dialogTitleId);
String dialogCancelId = "com.tencent.mm:id/aer";
AccessibilityNodeInfo targetCancel = AccessibilityHelper.findNodeInfosById(nodeInfo, dialogCancelId);
String dialogConfirmId = "com.tencent.mm:id/aes";
AccessibilityNodeInfo targetConfirm = AccessibilityHelper.findNodeInfosById(nodeInfo, dialogConfirmId);
if (targetCancel != null && targetConfirm != null && targetTitle != null &&
targetTitle.getText() != null && targetTitle.getText().toString().trim().contains("更新")) {
if (targetCancel.getText().toString().trim().contains("取消")) {
AccessibilityHelper.performClick(targetCancel);
} else if (targetConfirm.getText().toString().trim().contains("是")) {
AccessibilityHelper.performClick(targetConfirm);
}
return;
}
if (isSend) {
//聊天界面---右上角图片
String chattingId = "com.tencent.mm:id/fk";
AccessibilityNodeInfo targetChatting = AccessibilityHelper.findNodeInfosById(nodeInfo, chattingId);
//详细资料界面---微信号
String wxNoId = "com.tencent.mm:id/agb";
AccessibilityNodeInfo targetWxNo = AccessibilityHelper.findNodeInfosById(nodeInfo, wxNoId);
//详细资料界面---设置备注
String wxSetBzId = "com.tencent.mm:id/agr";
AccessibilityNodeInfo targetSetBz = AccessibilityHelper.findNodeInfosById(nodeInfo, wxSetBzId);
//详细资料界面---昵称
String wxNickId = "com.tencent.mm:id/agl";
AccessibilityNodeInfo targetNick = AccessibilityHelper.findNodeInfosById(nodeInfo, wxNickId);
//详细资料界面---备注
String wxBzId = "com.tencent.mm:id/ms";
AccessibilityNodeInfo targetBz = AccessibilityHelper.findNodeInfosById(nodeInfo, wxBzId);
//设置备注界面---设置备注输入框
String setEtId = "com.tencent.mm:id/ahu";
AccessibilityNodeInfo targetSetEt = AccessibilityHelper.findNodeInfosById(nodeInfo, setEtId);
if (targetChatting != null) {
String wxSendId = "com.tencent.mm:id/a5k";
AccessibilityNodeInfo targetSend = AccessibilityHelper.findNodeInfosById(nodeInfo, wxSendId);
if (StringUtil.isBlank(wxNoStr)) {