溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Android基于AccessibilityService怎么制作釘釘自動(dòng)簽到程序

發(fā)布時(shí)間:2021-06-17 13:38:34 來(lái)源:億速云 閱讀:231 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章給大家分享的是有關(guān)Android基于AccessibilityService怎么制作釘釘自動(dòng)簽到程序的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

首先分析一下,阿里釘釘?shù)暮灥搅鞒蹋?
打開(kāi)阿里釘釘->廣告頁(yè)停留2S左右->進(jìn)入主頁(yè)->點(diǎn)擊“工作”tab->點(diǎn)擊“簽到”模塊->進(jìn)入簽到頁(yè)面(可能會(huì)再次出現(xiàn)廣告和對(duì)話框)->點(diǎn)擊簽到

我們操作手機(jī)的過(guò)程就是這樣,要實(shí)現(xiàn)這些點(diǎn)擊,很自然想起了前段時(shí)間做的微信搶紅包小應(yīng)用,利用AccessibilityService服務(wù)幫助我們實(shí)現(xiàn)這些自動(dòng)化操作。

以上是分析過(guò)程,接下來(lái)是我對(duì)這個(gè)小功能實(shí)現(xiàn)的具體方案思路:

將測(cè)試手機(jī)放公司并且安裝這個(gè)應(yīng)用,通過(guò)我遠(yuǎn)程的電話撥打或者短信發(fā)送到測(cè)試手機(jī)(只要能產(chǎn)生廣播或者信息的就行),測(cè)試手機(jī)接受到廣播信息,喚醒釘釘,進(jìn)入釘釘頁(yè)面,AccessibilityService開(kāi)始工作,進(jìn)行一系列點(diǎn)擊簽到操作,結(jié)束操作后退出釘釘,簽到完成。

通過(guò)以上過(guò)程的分析我們大概要用到的知識(shí)有以下幾塊:

1.  喚醒非自己的其他第三方應(yīng)用

2.  廣播

3.  AccessibilityService服務(wù) 

以下是對(duì)這三部分代碼實(shí)現(xiàn):

喚醒第三方應(yīng)用

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先注冊(cè)監(jiān)聽(tīng)器

 <!-- 注冊(cè)監(jiān)聽(tīng)手機(jī)狀態(tài) --> 
  <receiver android:name=".PhoneReceiver"> 
   <intent-filter android:priority="1000" > 
    <action android:name="android.intent.action.PHONE_STATE" /> 
   </intent-filter> 
  </receiver>

相關(guān)權(quán)限

<!-- 讀取手機(jī)狀態(tài)的權(quán)限 --> 
 <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 {
   // 如果是來(lái)電
   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(你的手機(jī)號(hào))){
     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服務(wù)實(shí)現(xiàn):

相關(guān)權(quán)限及注冊(cè): 

<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文件夾下新建一個(gè)xml文件夾里面放入一個(gè)這樣的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.打開(kāi)釘釘
  * 2.確保當(dāng)前頁(yè)是主頁(yè)界面
  * 3.找到“工作”tab并且點(diǎn)擊
  * 4.確保到達(dá)簽到頁(yè)面
  * 5.找到簽到按鈕,并且點(diǎn)擊
  * 6.判斷簽到是否成功
  *  1.成功,退出程序
  *  2.失敗,返回到主頁(yè),重新從1開(kāi)始簽到
  */
 @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: //進(jìn)入主頁(yè)
    OpenHome(event.getEventType(),nodeInfo);
   break;
  case 2: //進(jìn)入簽到頁(yè)
   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){
   //判斷當(dāng)前是否是釘釘主頁(yè)
   List<AccessibilityNodeInfo> homeList = nodeInfo.findAccessibilityNodeInfosByText("工作");
   if(!homeList.isEmpty()){
    //點(diǎn)擊
     boolean isHome = click( "工作");
     System.out.println("---->"+isHome);
    index = 2;
    System.out.println("點(diǎn)擊進(jìn)入主頁(yè)簽到");
   }
  }
 }
 private void OpenQianDao(int type,AccessibilityNodeInfo nodeInfo) {
  if(type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED){
   //判斷當(dāng)前是否是主頁(yè)的簽到頁(yè)
   List<AccessibilityNodeInfo> qianList = nodeInfo.findAccessibilityNodeInfosByText("工作");
   if(!qianList.isEmpty()){
     boolean ret = click( "簽到");
     index = 3;
     System.out.println("點(diǎn)擊進(jìn)入簽到頁(yè)面詳情");
   }

//   index = ret?3:1; 
  }
 }
 private void doQianDao(int type,AccessibilityNodeInfo nodeInfo) {
  if(type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED){
   //判斷當(dāng)前頁(yè)是否是簽到頁(yè)
   List<AccessibilityNodeInfo> case1 = nodeInfo.findAccessibilityNodeInfosByText("開(kāi)啟我的簽到之旅");
   if(!case1.isEmpty()){
    click("開(kāi)啟我的簽到之旅");
    System.out.println("點(diǎn)擊簽到之旅");
   }
   List<AccessibilityNodeInfo> case2 = nodeInfo.findAccessibilityNodeInfosByText("我知道了");
   if(!case2.isEmpty()){
    click("我知道了");
    System.out.println("點(diǎn)擊我知道對(duì)話框");
   }
   List<AccessibilityNodeInfo> case3 = nodeInfo.findAccessibilityNodeInfosByText("簽到");
   if(!case3.isEmpty()){
    Toast.makeText(getApplicationContext(), "發(fā)現(xiàn)目標(biāo)啦??!~~", 1).show();
    System.out.println("發(fā)現(xiàn)目標(biāo)啦!");
    click("簽到");
    isFinish = true;
   }
  }

//  if(type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){
//   List<AccessibilityNodeInfo> case3 = nodeInfo.findAccessibilityNodeInfosByText("簽到");
//   if(!case3.isEmpty()){
//    Toast.makeText(getApplicationContext(), "發(fā)現(xiàn)目標(biāo)啦??!~~", 1).show();
//   }
//  }
 }
 //通過(guò)文字點(diǎn)擊
 private boolean click(String viewText){
   AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
  if(nodeInfo == null) {
    Log.w(TAG, "點(diǎn)擊失敗,rootWindow為空");
    return false;
  }
  List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(viewText);
  if(list.isEmpty()){
   //沒(méi)有該文字的控件
    Log.w(TAG, "點(diǎn)擊失敗,"+viewText+"控件列表為空");
    return false;
  }else{
   //有該控件
   //找到可點(diǎn)擊的父控件
   AccessibilityNodeInfo view = list.get(0);
   return onclick(view); //遍歷點(diǎn)擊
  }
 }
 private boolean onclick(AccessibilityNodeInfo view){
  if(view.isClickable()){
   view.performAction(AccessibilityNodeInfo.ACTION_CLICK);
    Log.w(TAG, "點(diǎn)擊成功");
    return true;
  }else{
   AccessibilityNodeInfo parent = view.getParent();
   if(parent==null){
    return false;
   }
   onclick(parent);
  }
  return false;
 }
 //點(diǎn)擊返回按鈕事件
 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(), "服務(wù)可用開(kāi)啟!", 1).show();
  index = 1;
 }
}

感謝各位的閱讀!關(guān)于“Android基于AccessibilityService怎么制作釘釘自動(dòng)簽到程序”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI