前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何编写基于Android的AccessibilityService的自动打卡

如何编写基于Android的AccessibilityService的自动打卡

作者头像
用户1148881
发布2018-01-17 15:08:24
6.4K1
发布2018-01-17 15:08:24
举报
文章被收录于专栏:jianhuicodejianhuicodejianhuicode

第一节 缘由与准备 

最近有时间空闲,闲来无事,想到使用钉钉打卡有时会迟到,所以周末的时候去看了相关网上资料,做了个demo。

材料:定时器,AccessibilityService

加工方案:使用定时器在签到签退期间内自启,通过AccessibilityService模拟点击:分为签到与签退两种情况。

签到正常流程:工作-》考勤打卡-》(判断是否弹出窗口-是:我知道了否跳过)-》签到。

签到迟到流程:工作-》考勤打卡-》迟到打卡。

签退正常流程:工作-》考勤打卡-》签退。

工艺难点:签到页中嵌套的是基于WebView的页面,一开始以为无法获取节点,想到通过屏幕中的位置去点击那块区域,查看官方文档发现有个方法getAccessibilityNodeProvider(),得到虚拟节点进行模拟点击。

第二节:热火朝天

技能点:判断应用状态,启动指定应用,自定义AccessibilityService控制模拟点击流程

判断应用状态:

 public static boolean isBackground(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.processName.equals(context.getPackageName())) {
                if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
                    Log.i("后台", appProcess.processName);
                    return true;
                }else{
                    Log.i("前台", appProcess.processName);
                    return false;
                }
            }
        }
        return false;
    }

启动指定应用:

 public static void doStartApplicationWithPackageName(Context context, String packagename) {

        // 通过包名获取此APP详细信息,包括Activities、services、versioncode、name等等
        PackageInfo packageinfo = null;
        try {
            packageinfo = context.getPackageManager().getPackageInfo(packagename, 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (packageinfo == null) {
            return;
        }

        // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
        Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
        resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        resolveIntent.setPackage(packageinfo.packageName);

        // 通过getPackageManager()的queryIntentActivities方法遍历
        List<ResolveInfo> resolveinfoList = context.getPackageManager()
                .queryIntentActivities(resolveIntent, 0);

        ResolveInfo resolveinfo = resolveinfoList.iterator().next();
        if (resolveinfo != null) {
            // packagename = 参数packname
            String packageName = resolveinfo.activityInfo.packageName;
            // 这个就是我们要找的该APP的LAUNCHER的Activity[组织形式:packagename.mainActivityname]
            String className = resolveinfo.activityInfo.name;
            // LAUNCHER Intent
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);

            // 设置ComponentName参数1:packagename参数2:MainActivity路径
            ComponentName cn = new ComponentName(packageName, className);

            intent.setComponent(cn);
            context.startActivity(intent);
        }
    }

自定义AccessibilityService控制模拟点击流程:

1.获取点击控件对象(可以通过文本不推荐通过资源id方式点击)

工作布局的资源ID:

考勤打卡布局的资源ID(这个id是动态生成的8个都是):

考勤打卡布局的资源ID:

2窗口发生变化处理:

 @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        if(isFinish){
            return;
        }
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if(nodeInfo == null) {
            Log.d(TAG, "rootWindow为空");
            return ;
        }
        switch (accessibilityEvent.getEventType()){
            //当窗口的状态发生改变时
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
               if (index==1) {
                    //主页点击工作
                   clickHome(nodeInfo,accessibilityEvent);
                   Log.d(TAG,"工作");
                } else  if (index==2) {
                    //工作tab点击考勤打卡
                   clickKaoQing(nodeInfo,accessibilityEvent);
                   Log.d(TAG,"点击考勤打卡");
                } else  if (index==3) {
                    //开始打卡
                   clickKaoQingBtn(nodeInfo,accessibilityEvent);
                   Log.d(TAG,"打卡");
                }
                break;
        }

    }

3后续处理:

发现考勤打卡页面是基于webview的h5页面,因此暂时没有好的方法,获取webview对象,以及获取虚拟节点。

不过如果可以获取到窗口下的webview对象,那么是可以获取页面的虚拟节点,进行模拟点击。打卡是没问题的,由于现在极速打卡的功能,打开应用自动签到。

参考:

>Android WebView官方文档

>Android AccessibilityNodeProvider官方文档

>基于AccessibilityService制作的钉钉自动签到程序

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-06-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一节 缘由与准备 
  • 最近有时间空闲,闲来无事,想到使用钉钉打卡有时会迟到,所以周末的时候去看了相关网上资料,做了个demo。
  • 材料:定时器,AccessibilityService
  • 加工方案:使用定时器在签到签退期间内自启,通过AccessibilityService模拟点击:分为签到与签退两种情况。
  • 签到正常流程:工作-》考勤打卡-》(判断是否弹出窗口-是:我知道了否跳过)-》签到。
  • 签到迟到流程:工作-》考勤打卡-》迟到打卡。
  • 签退正常流程:工作-》考勤打卡-》签退。
  • 工艺难点:签到页中嵌套的是基于WebView的页面,一开始以为无法获取节点,想到通过屏幕中的位置去点击那块区域,查看官方文档发现有个方法getAccessibilityNodeProvider(),得到虚拟节点进行模拟点击。
  • 第二节:热火朝天
  • 技能点:判断应用状态,启动指定应用,自定义AccessibilityService控制模拟点击流程
  • 判断应用状态:
  • 启动指定应用:
  • 自定义AccessibilityService控制模拟点击流程:
  • 1.获取点击控件对象(可以通过文本不推荐通过资源id方式点击)
  • 工作布局的资源ID:
  • 考勤打卡布局的资源ID(这个id是动态生成的8个都是):
  • 考勤打卡布局的资源ID:
  • 2窗口发生变化处理:
  • 3后续处理:
  • 发现考勤打卡页面是基于webview的h5页面,因此暂时没有好的方法,获取webview对象,以及获取虚拟节点。
  • 不过如果可以获取到窗口下的webview对象,那么是可以获取页面的虚拟节点,进行模拟点击。打卡是没问题的,由于现在极速打卡的功能,打开应用自动签到。
  • 参考:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档