手机辅助功能实现抢微信红包

辅助功能服务AccessibilityService

Posted by JovenHe on January 21, 2020

19年下半年就没怎么写过文章了,因为10月份换了工作,开始做政企手机管控相关的工作,有太多需要学习的东西,自己本身就是个菜鸟,所以一直没时间写

最近都是开年会的开年会,聚餐的聚餐,相信大家都没少抢红包,我也利用最近所学做了一个小功能来抢红包,用的就是 辅助功能服务AccessibilityService,这个东西就算是纯粹的Android开发者也很少用,功能就相当于Xposed,但它是Android自带的服务,目的在于帮助那些具有视觉、身体或年龄相关限制的用户更轻松的使用Android设备和应用,它一般提供了页面元素查找功能和元素点击功能。在我工作项目中就用于自动始终允许权限、自动允许使用情况访问权、自动允许显示在其他应用上层等权限

下面我们就开始通过AccessibilityService来做一个抢红包的APP

声明服务

新建一个Service,继承自 AccessibilityService,主要逻辑都是在onAccessibilityEvent方法中进行,代表界面发生某些事件就会触发该方法,例如点击、长按、触摸、焦点、滑动等等事件

public class HandleAccessService extends AccessibilityService {

    private static final String TAG = "HandleAccessService";

    private Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this.getApplicationContext();
    }
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {

    }
    @Override
    public void onInterrupt() {

    }

}

在清单文件中注册,

		<service
            android:name=".service.HandleAccessService"
            android:label="@string/accessibility_control_service_label"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config" />

            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
        </service>

label是服务名,permission代表需要辅助功能服务,meta-data中的resource指服务说明

主要方法

以下列举的只是我刚接触到的常用方法,还是有很多很重要的方法的,可以查官方文档进行学习

getRootInActiveWindow

获取窗体中的节点信息,会获取到当前窗体的所有view节点

findAccessibilityNodeInfosByViewId

通过ViewID找到节点信息

findAccessibilityNodeInfosByText

通过文本找到节点信息

getParent()

获取该节点的父节点

performAction

对该节点执行对应操作,例如点击、获取焦点、设置文本

分析

辅助服务来抢红包就是对界面元素分析后,针对未抢的红包节点View进行模拟点击,以此来实现

用于开发辅助的重要工具就是Android Device Monitor,可以在AndroidSDK->tools->monitor.bat打开

可以看到是可以进行view树的分析的,可以查看选中view的详细信息、节点树的嵌套信息

代码实现

点击红包消息

可以看到红包消息与其他消息的不同点是红包消息的底部有一个“微信红包”,可以以此来找到红包节点,而且未领取的红包上的文本是“领取红包”,可以以此避免重复点击红包

		AccessibilityNodeInfo mRootNode = getRootInActiveWindow();
        if (mRootNode != null) {
            
        
            List<AccessibilityNodeInfo> luckyMoneyNode = mRootNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/afp");
            if (luckyMoneyNode != null && !luckyMoneyNode.isEmpty()) {
                for (AccessibilityNodeInfo accessibilityNodeInfo : luckyMoneyNode) {
                    if (accessibilityNodeInfo.getText().toString().equals("微信红包")) {
                        List<AccessibilityNodeInfo> getNode = accessibilityNodeInfo.getParent().getParent().findAccessibilityNodeInfosByText("领取红包");
                        if (getNode != null && !getNode.isEmpty()) {
                            accessibilityNodeInfo.getParent().getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            break;
                        }
                    }
                }
            }
            mRootNode.recycle();
        }
打开红包

这一步直接点击就行,找到开的按钮进行点击

List<AccessibilityNodeInfo> childNodes = mRootNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/c85");
            if (childNodes != null && childNodes.size() != 0) {
                childNodes.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
红包详情页直接返回
List<AccessibilityNodeInfo> toolbarTextNodes = mRootNode.findAccessibilityNodeInfosByViewId("android:id/text1");
if (toolbarTextNodes != null && toolbarTextNodes.size() != 0) {
    if (toolbarTextNodes.get(0).equals("红包详情")) {   
        toolbarTextNodes.get(0).getParent().getParent().findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ht").get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);    
    }
}

使用

打包后直接安装到手机,然后在设置中的只能辅助-无障碍中找到该服务名,打开辅助就可以了

效果

可以看到在收到红包的一瞬间就被打开并领取成功,但因为某些原因还是关闭后又被重新打开,我个人猜测是由于在红包详情页点击返回时因为“领取红包”变为“红包已领取“的间隔内接收到了事件,导致红包被点击,所以弹出红包已领取,所以应该在代码中加一秒的时间差,自动点击领取后的一秒内不要自动点击,给控件一定的反应时间

总结