当前位置:Gxlcms > 数据库问题 > 基于AccessibilityService制作的钉钉自动签到程序

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

时间:2021-07-01 10:21:17 帮助过:23人阅读

基于AccessibilityService制作的钉钉自动签到程序 标签: 移动开发安卓自动化操作 2015-12-03 09:56 1736人阅读 评论(10) 收藏 举报 分类: Android(3)  版权声明:本文为博主原创文章,未经博主允许不得转载。前两天公司开始宣布要使用阿里钉钉来签到啦!!!~~这就意味着,我必须老老实实每天按时签到上班下班了,这真是一个悲伤的消息,可是!!!!那么机智(lan)的我,怎么可能就这么屈服!!!阿里钉钉签到,说到底不就是手机软件签到吗?我就是干移动开发的,做一个小应用每天自动签到不就行了:)说干就干,首先分析一下,阿里钉钉的签到流程: 打开阿里钉钉->广告页停留2S左右->进入主页->点击“工作”tab->点击“签到”模块->进入签到页面(可能会再次出现广告和对话框)->点击签到我们操作手机的过程就是这样,要实现这些点击,很自然想起了前段时间做的微信抢红包小应用,利用AccessibilityService服务帮助我们实现这些自动化操作。以上是分析过程,接下来是我对这个小功能实现的具体方案思路:将测试手机放公司并且安装这个应用,通过我远程的电话拨打或者短信发送到测试手机(只要能产生广播或者信息的就行),测试手机接受到广播信息,唤醒钉钉,进入钉钉页面,AccessibilityService开始工作,进行一系列点击签到操作,结束操作后退出钉钉,签到完成。通过以上过程的分析我们大概要用到的知识有以下几块:唤醒非自己的其他第三方应用广播AccessibilityService服务 以下是对这三部分代码实现:唤醒第三方应用package net.fenzz.dingplug; import java.util.List; import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.content.pm.ResolveInfo; public class Utils {     public static void openCLD(String packageName,Context context) {         PackageManager packageManager = context.getPackageManager();         PackageInfo pi = null;                try {                  pi = packageManager.getPackageInfo("com.alibaba.android.rimet", 0);             } catch (NameNotFoundException e) {              }             Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);             resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);             resolveIntent.setPackage(pi.packageName);              List<ResolveInfo> apps = packageManager.queryIntentActivities(resolveIntent, 0);              ResolveInfo ri = apps.iterator().next();             if (ri != null ) {                 String className = ri.activityInfo.name;                  Intent intent = new Intent(Intent.ACTION_MAIN);                 intent.addCategory(Intent.CATEGORY_LAUNCHER);                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                ComponentName cn = new ComponentName(packageName, className);                  intent.setComponent(cn);                 context.startActivity(intent);             }     }  }
接受电话广播并且唤醒钉钉:mainifest先注册监听器  <!-- 注册监听手机状态 -->          <receiver android:name=".PhoneReceiver">              <intent-filter android:priority="1000" >                  <action android:name="android.intent.action.PHONE_STATE" />              </intent-filter>          </receiver> 
相关权限 <!-- 读取手机状态的权限 -->      <uses-permission android:name="android.permission.READ_PHONE_STATE" />       <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
代码package net.fenzz.dingplug; import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.telephony.TelephonyManager;import android.app.Service;import android.util.Log; public class PhoneReceiver extends BroadcastReceiver {     private static final String TAG = "message";    private static boolean mIncomingFlag = false;    private static String mIncomingNumber = null;     @Override    public void onReceive(Context context, Intent intent) {        // 如果是拨打电话        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {            mIncomingFlag = false;            String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);            Log.i(TAG, "call OUT:" + phoneNumber);         } else {            // 如果是来电            TelephonyManager tManager = (TelephonyManager) context                    .getSystemService(Service.TELEPHONY_SERVICE);            switch (tManager.getCallState()) {             case TelephonyManager.CALL_STATE_RINGING:                mIncomingNumber = intent.getStringExtra("incoming_number");                Log.i(TAG, "RINGING :" + mIncomingNumber);                if(mIncomingNumber!=null&&mIncomingNumber.equals(你的手机号)){                    Utils.openCLD("com.alibaba.android.rimet", context);                    DingService.instance.setServiceEnable();                }                break;            case TelephonyManager.CALL_STATE_OFFHOOK:                if (mIncomingFlag) {                    Log.i(TAG, "incoming ACCEPT :" + mIncomingNumber);                }                break;            case TelephonyManager.CALL_STATE_IDLE:                if (mIncomingFlag) {                    Log.i(TAG, "incoming IDLE");                }                break;            }        }}AccessibilityService服务实现: 相关权限及注册: <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <service            android:name=".DingService"            android:enabled="true"            android:exported="true"            android:label="@string/app_name"            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >            <intent-filter>                <action android:name="android.accessibilityservice.AccessibilityService" />            </intent-filter>             <meta-data                android:name="android.accessibilityservice"                android:resource="@xml/red_service_config" /> </service>
需要在res文件夹下新建一个xml文件夹里面放入一个这样的xml配置文件:<?xml version="1.0" encoding="utf-8"?><accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"    android:accessibilityEventTypes="typeAllMask"    android:accessibilityFeedbackType="feedbackGeneric"    android:accessibilityFlags="flagDefault"    android:canRetrieveWindowContent="true"    android:description="@string/accessibility_description"    android:notificationTimeout="100"    android:packageNames="com.alibaba.android.rimet"      />
代码:package net.fenzz.dingplug; import java.util.ArrayList;import java.util.List; import android.accessibilityservice.AccessibilityService;import android.util.Log;import android.view.accessibility.AccessibilityEvent;import android.view.accessibility.AccessibilityNodeInfo;import android.widget.Toast; public class DingService extends AccessibilityService {     private String TAG = getClass().getSimpleName();     private  boolean  isFinish = false;     public static DingService instance;    private int index = 1;     /**     * 获取到短信通知     *  0.唤醒屏幕     *  1.打开钉钉     *  2.确保当前页是主页界面     *  3.找到“工作”tab并且点击     *  4.确保到达签到页面     *  5.找到签到按钮,并且点击     *  6.判断签到是否成功     *      1.成功,退出程序     *      2.失败,返回到主页,重新从1开始签到     */      @Override    public void onAccessibilityEvent(AccessibilityEvent event) {        // TODO Auto-generated method stub//       final int eventType = event.getEventType();         ArrayList<String> texts = new ArrayList<String>();            Log.i(TAG, "事件---->" + event.getEventType());           if(isFinish){            return;          }          AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();         if(nodeInfo == null) {                Log.w(TAG, "rootWindow为空");                return ;          }//       nodeInfo. //       System.out.println("nodeInfo"+nodeInfo);            System.out.println("index:"+index);         switch (index) {         case 1: //进入主页             OpenHome(event.getEventType(),nodeInfo);            break;        case 2: //进入签到页            OpenQianDao(event.getEventType(),nodeInfo);            break;        case 3:            doQianDao(event.getEventType(),nodeInfo);            break;         default:            break;        }     }      private ArrayList<String> getTextList(AccessibilityNodeInfo node,ArrayList<String> textList){        if(node == null) {            Log.w(TAG, "rootWindow为空");            return null;        }        if(textList==null){            textList = new ArrayList<String>();        }        String text = node.getText().toString();          if(text!=null&&text.equals("")){              textList.add(text);          }//        node.get        return null;     }      private void OpenHome(int type,AccessibilityNodeInfo nodeInfo) {        if(type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){            //判断当前是否是钉钉主页            List<AccessibilityNodeInfo> homeList = nodeInfo.findAccessibilityNodeInfosByText("工作");            if(!homeList.isEmpty()){                //点击                 boolean isHome = click( "工作");                 System.out.println("---->"+isHome);                index = 2;                System.out.println("点击进入主页签到");            }        }     }     private void OpenQianDao(int type,AccessibilityNodeInfo nodeInfo) {        if(type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED){            //判断当前是否是主页的签到页            List<AccessibilityNodeInfo> qianList = nodeInfo.findAccessibilityNodeInfosByText("工作");            if(!qianList.isEmpty()){                 boolean ret = click( "签到");                 index = 3;                 System.out.println("点击进入签到页面详情");            } //           index = ret?3:1;           }     }      private void doQianDao(int type,AccessibilityNodeInfo nodeInfo) {        if(type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED){            //判断当前页是否是签到页            List<AccessibilityNodeInfo> case1 = nodeInfo.findAccessibilityNodeInfosByText("开启我的签到之旅");            if(!case1.isEmpty()){                click("开启我的签到之旅");                System.out.println("点击签到之旅");            }             List<AccessibilityNodeInfo> case2 = nodeInfo.findAccessibilityNodeInfosByText("我知道了");            if(!case2.isEmpty()){                click("我知道了");                System.out.println("点击我知道对话框");            }            List<AccessibilityNodeInfo> case3 = nodeInfo.findAccessibilityNodeInfosByText("签到");            if(!case3.isEmpty()){                Toast.makeText(getApplicationContext(), "发现目标啦!!~~", 1).show();                System.out.println("发现目标啦!");                click("签到");                isFinish = true;            }        } //      if(type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){//          List<AccessibilityNodeInfo> case3 = nodeInfo.findAccessibilityNodeInfosByText("签到");//          if(!case3.isEmpty()){//              Toast.makeText(getApplicationContext(), "发现目标啦!!~~", 1).show();//          }//      }     }      //通过文字点击    private boolean click(String viewText){         AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();        if(nodeInfo == null) {                Log.w(TAG, "点击失败,rootWindow为空");                return false;        }        List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(viewText);        if(list.isEmpty()){            //没有该文字的控件             Log.w(TAG, "点击失败,"+viewText+"控件列表为空");             return false;        }else{            //有该控件            //找到可点击的父控件            AccessibilityNodeInfo view = list.get(0);            return onclick(view);  //遍历点击        }     }     private boolean onclick(AccessibilityNodeInfo view){        if(view.isClickable()){            view.performAction(AccessibilityNodeInfo.ACTION_CLICK);             Log.w(TAG, "点击成功");             return true;        }else{             AccessibilityNodeInfo parent = view.getParent();            if(parent==null){                return false;            }            onclick(parent);        }        return false;    }     //点击返回按钮事件    private void back(){         performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);    }     @Override    public void onInterrupt() {        // TODO Auto-generated method stub     }     @Override    protected void onServiceConnected() {        // TODO Auto-generated method stub        super.onServiceConnected();        Log.i(TAG, "service connected!");        Toast.makeText(getApplicationContext(), "连接成功!", 1).show();        instance = this;    }     public void setServiceEnable(){        isFinish = false;        Toast.makeText(getApplicationContext(), "服务可用开启!", 1).show();        index = 1;    } }
以上基本是所有代码,这个小程序中可以不用Activity组件,也可以加一个小的Activity,用来作为系统的总开关,当然也可以自动检测时间,来判断是否开启服务,这样就不用Activity了,在这个小例子中,我使用了一个小activity,就放了一个button。项目源码,我稍后上传!

null

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

标签:encoding   阿里   获取   esc   ini   not   one   java   来电   

人气教程排行