android AccessibilityService的学习和应用

最近公司要用钉钉作为打卡工具,说好的弹性上班呢,于是乎想找个破解方法,百度了一圈,有个大神的文章可以解决此问题,文章地址:

http://blog.csdn.net/fenzzz/article/details/50156697 点击打开链接

原来和微信抢红包一样里面用到了一个非常关键的类 AccessibilityService,这个类的作用就是监听屏幕发生各种改变事件,比如手机打开红包页面,当一旦出现红包就自动去模拟点击红包,肯定比人为速度更快,那么钉钉打卡一样的原理,比如早上9点设置一个定时器或者给安卓了钉钉的手机打个电话神马的,然后去触发打开钉钉,然后检测到页面相应的变化去处理,一步一步的就可以到打卡页面打卡了,这里贴下根据大神的代码稍微改动了一点点,

代码很简单,稍微看一下就能明白其中原理。

这里主要用到了3个知识点,

一、根据包名打开APP

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);
        }
    }

}
二、注册一个广播接受者,用于接受电话短信之类的广播

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("15606708596")){
                        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,重写@Override
public void onAccessibilityEvent(AccessibilityEvent event);event包含了整个屏幕变化的监听事件,可以根据这些事件来处理自己想要的操作


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("点击进入主页签到");
				Log.d(TAG, "点击进入主页签到");
			}
		}
	}

	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("点击进入签到页面详情");
				Log.d(TAG, "点击进入点击进入签到页面详情");
			}
//			 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("更新打卡>");

			Log.d(TAG, "case1 " + case1 + "case2 " + case2 + "case3 " + case3);
			if(!case1.isEmpty() && !case2.isEmpty() && !case3.isEmpty()){
				Toast.makeText(getApplicationContext(), "发现目标啦!!~~", Toast.LENGTH_SHORT).show();
				System.out.println("发现目标啦!");
				Log.d(TAG, "发现目标啦!");
				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(), "连接成功!", Toast.LENGTH_SHORT).show();
		instance = this;
	}

	public void setServiceEnable(){
		isFinish = false;
		Toast.makeText(getApplicationContext(), "服务可用开启!", Toast.LENGTH_SHORT).show();
		index = 1;
	}
}

注意:运行安装好这个项目后,以华为手机为例,须要在手机设置——高级设置——辅助功能找个这个APP然后开启AccessibilityService这个服务,不然运行了程序会报空指针,说AccessibilityService为空。

好了,又可以愉快玩耍了

钉钉打卡项目地址:http://download.csdn.net/download/msn465780/10017453 点击打开链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值