钉钉怎么设置自动签到
发布网友
发布时间:2022-04-22 08:18
我来回答
共2个回答
懂视网
时间:2022-05-01 23:13
基于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 来电
热心网友
时间:2022-05-01 20:21
签到是钉钉推出的一款方便销售等外勤人员签到的应用,用于外出人员定时报告位置使用的哦,打开【手机钉钉】-【工作】-【选择正确的团队】-【签到】即可开始签到。
签到的地点就是员工当前实时定位的地点,签到时候还可以让员工拍照哦。 目前不支持对国外进行地图定位签到,仅支持中国*及港澳台地区签到。
温馨提示:
1、签到一天最多可以签到100次,签到图片最多可以上传9张;
2、签到没有签退的概念,若是希望上下班打卡,建议使用【考勤打卡】应用;
3、无法自动签到哦,若忘记签到,无法补签,建议重新签到之后填写备注,或向管理员解释情况。
4、若您没有签到应用,建议查看页面上方,确认是否选择了正确的团队,或是找管理员确认是否停用了该应用;
5、签到地址是无法做更改的哦。
6、签到无法设置抄送人,您可以导出签到数据哦
7、无法禁止同一个地点重复签到。