最近要实现微信自动抢红包的功能,使用AccessibilityService来开发,这里主要写一下逻辑以及注意点。
注意点
1、搜索关键字
我们实现某个功能比如点击等需要找到对应的对象然后模拟点击事件,所以首先就是怎么样找到对象,下面说三种方式:
(1)findAccessibilityNodeInfosByText通过文字来实现查找,返回的是List<AccessibilityNodeInfo>,所以需要通过for循环来具体判断需要的关键字的对象
(2)findAccessibilityNodeInfosByViewId通过控件的id来查询,返回的是List<AccessibilityNodeInfo>,虽然也是返回List但是一般只有一个,查找的准确性高,不过需要系统的版本API>=18
findAccessibilityNodeInfosByText来查找,在微信中使用uiautomatorviewer查看布局,发现不同的手机相同的控件id是不一样的,比如我们需要查询获取红包的数量时,需要先查找'元',然后获取其父控件,然后查找金额所在的位置,这个是不变的。
2、对于返回功能
一般我们领取红包后进入红包详情界面,这时我们要返回到聊天界面使用uiautomatorviewer查看返回箭头,查看其属性他的clickable=false这样的话我们就无法通过
accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);来实现点击事件来实现返回的功能,不过查看AccessibilityService源码里面有对应的全局事件,下面说两种实现返回功能的方法
/**
* Performs a global action. Such an action can be performed
* at any moment regardless of the current application or user
* location in that application. For example going back, going
* home, opening recents, etc.
*
* @param action The action to perform.
* @return Whether the action was successfully performed.
*
* @see #GLOBAL_ACTION_BACK
* @see #GLOBAL_ACTION_HOME
* @see #GLOBAL_ACTION_NOTIFICATIONS
* @see #GLOBAL_ACTION_RECENTS
*/
public final boolean performGlobalAction(int action) {
IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
if (connection != null) {
try {
return connection.performGlobalAction(action);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
}
}
return false;
}
/**
* 微信的包名
*/
static final String WECHAT_PACKAGENAME = "com.tencent.mm";
/**
* 拆红包类
*/
static final String WECHAT_RECEIVER_CALSS = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI";
/**
* 红包详情类
*/
static final String WECHAT_DETAIL = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI";
/**
* 微信主界面或者是聊天界面
*/
static final String WECHAT_LAUNCHER = "com.tencent.mm.ui.LauncherUI";
/**
* @param info 当前节点
* @param matchFlag 需要匹配的文字
* @param type 操作的类型
*/
public void recycle(AccessibilityNodeInfo info, String matchFlag, int type) {
if (info != null) {
if (info.getChildCount() == 0) {
CharSequence desrc = info.getContentDescription();
switch (type) {
case ENVELOPE_RETURN://返回
if (desrc != null && matchFlag.equals(info.getContentDescription().toString().trim())) {
if (info.isCheckable()) {
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else {
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
}
}
break;
}
} else {
int size = info.getChildCount();
for (int i = 0; i < size; i++) {
AccessibilityNodeInfo childInfo = info.getChild(i);
if (childInfo != null) {
Log.e(TAG, "index: " + i + " info" + childInfo.getClassName() + " : " + childInfo.getContentDescription()+" : "+info.getText());
recycle(childInfo, matchFlag, type);
}
}
}
}
}