安卓AccessibilityService实现蚂蚁森林自动收集能量 最新 多线程 + 手势 + 深搜webView

前言

最初,我有一个朋友问我能不能有办法监听到另一个App界面的内容,一旦有特定的消息出现就提醒用户,就这样,我接触到了AccessibityService。这个项目很好写,所以很快就实现了。主要是那个app结点都能直接获取到,也都能点击。有一天,我收蚂蚁森林能量,好友比较多,就在想,我能不能写一个基于AccessibilityService的自动收集能量的应用,造福一下懒人

程序员三大美德:懒惰、急躁、傲慢


运行效果

APP已放在末尾,欢迎大家测试
在这里插入图片描述


所用技术

AccessibilityService + 多线程 + 手势


项目开始

实现逻辑
在这里插入图片描述
说明
所有判断页面是否加载完成,用户名是否匹配的操作都是在开辟的子线程(图中绿色部分)中进行,主线程的MainHandler 接收来自子线程发送的消息,进行处理。


一些问题的解决

一、怎么获得webView中的结点信息

二、怎么判断webView加载完成了

三、怎么点击按钮


第一个问题,webView就像浏览器一样,里面的内容是网页的内容。

在webView中,所有的通过搜索获取结点List的方法失效了,但是可以通过不停地得到子节点、判断、得到子节点、判断的方法粗略的得到结点信息。

可以借助安卓的 uiautomatorviewer 工具查看结点树,但是这里的结点树也可能和实际运行的有点点出入,主要是webview 加载成功和不成功 之间有些变化,其他的结点结构是固定的,所以可取。

我是用dfs的方式得到webView的结点

private AccessibilityNodeInfo returnWebView(AccessibilityNodeInfo nowNode){
    if(nowNode==null) return null;

    if(nowNode.getClassName().toString().equals("android.webkit.WebView")){
        return nowNode;
    }
    if(nowNode.getChildCount()==0) return null;
    
    int size = nowNode.getChildCount();
    AccessibilityNodeInfo webViewNode = null;
    for(int i=0;i<size;i++){
        webViewNode = returnWebView(nowNode.getChild(i));
        if(webViewNode!=null) return webViewNode;
    }
    return null;
}

uiautomatorviewer具体怎么使用网上有很多博客,就不说了


第二个问题,怎么判断webView是否加载完成。

老实说,没有特别好的办法。你看一般的浏览器加载网页,有些时候加载的快,有些时候加载得慢,网页上很多东西的加载都是异步的。我很难准确的找到一个判定条件说网页绝对加载完成了。我用的办法是子线程判断关键信息是否加载完成了,只要我要点击的按钮加载完成了,就判定webView加载完成了。

private void LoadingForest(){
    //判定已载入的规则:只包含能量的view节点子孩子数大于等于4
    new Thread(new Runnable() {
        @Override
        public void run() {
        debug("加载蚂蚁森林...");
        Message message = Message.obtain();
        int MaxCount = MAX_REQUEST_TIME;
        WebViewNode = null;
        while(MaxCount > 0 ){
            MaxCount--;
            sleep(500);
            rootNode = getRootInActiveWindow();//Frame
            if(rootNode==null || rootNode.getChildCount()==0) continue;
            WebViewNode = returnWebView(rootNode);
            if(WebViewNode==null || WebViewNode.getChildCount()==0) continue;
            nowNode = WebViewNode.getChild(0);
            if(nowNode==null || nowNode.getChildCount()==0) continue;
            nowNode = nowNode.getChild(0);
            if (nowNode==null || nowNode.getChildCount()<3) continue;
            nowNode = nowNode.getChild(2);
//                        dfs(nowNode);
            if(nowNode.getChildCount()>=4) break;
        }
        if(MaxCount==0){
            message.what = -1;
        }else{
            message.what = 6;
        }
        MainHandler.sendMessage(message);
        }
    }).start();
}

第三个问题 ,怎么点击

通过手势,可以实现滑动 和点击

滑动

private void scroll(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            int sx = (nowUserEntrance.left+nowUserEntrance.right)>>1;
            int sy = nowUserEntrance.bottom;
            int ey = nowUserEntrance.top-21;
            dispatchGestureScroll(2,sx,sy,sx,ey);
            sleep(100);
            Message message = Message.obtain();
            message.what = 10;
            MainHandler.sendMessage(message);
        }
    }).start();
}

private void dispatchGestureScroll(final int flag, int sx, int sy,int ex,int ey) {
//        debug("sx:"+sx+"sy:"+sy+"ex:"+ex+"ey:"+ey);
    GestureDescription.Builder builder = new GestureDescription.Builder();
    Path p = new Path();
    p.moveTo(sx, sy);
    p.lineTo(ex, ey);
    builder.addStroke(new GestureDescription.StrokeDescription(p, 0L, 100L));
    GestureDescription gesture = builder.build();
    dispatchGesture(gesture, new AccessibilityService.GestureResultCallback() {
        @Override
        public void onCompleted(GestureDescription gestureDescription) {
            super.onCompleted(gestureDescription);
            Log.d(TAG, flag+"onCompleted: 完成..........");
        }

        @Override
        public void onCancelled(GestureDescription gestureDescription) {
            super.onCancelled(gestureDescription);
            Log.d(TAG, flag+"onCompleted: 取消..........");
        }
    }, null);
}

点击

/**
 * 模拟点击事件
 * @param flag 点击的控件类型(1 能量) (0 用户入口)
 * @param x 横坐标
 * @param y 纵坐标
 */
private boolean dispatchGestureView(final int flag, int x, int y) {
    boolean res = false;
    GestureDescription.Builder builder = new GestureDescription.Builder();
    Path p = new Path();
    p.moveTo(x, y);
    p.lineTo(x, y);
    builder.addStroke(new GestureDescription.StrokeDescription(p, 0L, 100L));
    GestureDescription gesture = builder.build();
    Log.d("","点击了位置"+"("+x+","+y+")");
    sleep(200);
    res = dispatchGesture(gesture, new GestureResultCallback(){}, null);
    return res;
}

暂时就写到这儿

APP 在下方,欢迎大家测试。有BUG私信告诉我,谢谢。
蚂蚁森林自动手机能量
提取码:0gxf

发布了7 篇原创文章 · 获赞 15 · 访问量 760

猜你喜欢

转载自blog.csdn.net/weixin_42474371/article/details/104290924
今日推荐