最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android后臺模擬點擊探索(附源碼)

 更新時間:2018年01月24日 12:04:05   作者:披薩大叔  
這篇文章主要介紹了Android后臺模擬點擊探索(附源碼),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

工作中我們需要自制一套工具,其中遇到需要模擬點擊事件的需求,類似按鍵精靈的功能,支持后臺持續(xù)運行,滿足觸發(fā)條件時完成點擊。

經(jīng)過一番探索,一共整理出兩種不同的方案:AccessibilityService 和 adb shell命令,讀者可自行選擇合適的場景。

AccessibilityService

無障礙模式是我首先想到的方案,對于不知道Android無障礙模式的,可自行百度。這里簡單說明一下,AccessibilityService是Android為殘障人士提供的貼心功能,比如可以報出當前頁面有哪些按鈕balabala。使用官方提供的一些列API,我們還可以完成一些自動運行的“黑科技”操作,比如早些年的紅包插件、微信自動回復插件、自動點贊插件等。

本方案原理比較簡單:掃描當前頁面的View樹,找到目標控件,模擬點擊操作,下面詳細闡述。

添加配置文件

首先需要在res目錄下建立配置文件:accessible_service_config.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="flagReportViewIds"
 android:canRetrieveWindowContent="true"
 android:notificationTimeout="100"
 android:description="@string/description"
 android:packageNames="目標包名"/>

accessibilityEventTypes:設置響應事件的類型,這里設置typeAllMask,就是響應全部類型的事件。

accessibilityFeedbackType:設置回饋給用戶的方式,有語音播出和振動,這里使用通用類型。

notificationTimeout:設置響應時間。

packageNames:目標包名,比如紅包插件就要設置微信包名,關于包名如何獲取,下文會提到。

繼承AccessibilityService編碼

接著我們繼承AccessibilityService新建AutoClickAccessibilityService,重寫onAccessibilityEvent(AccessibilityEvent event)。

public class AutoClickAccessibilityService extends AccessibilityService {
 private static final String TAG = "GK";

 @Override
 public void onAccessibilityEvent(AccessibilityEvent event) {
  ztLog("===start===");
  try {
   //拿到根節(jié)點
   AccessibilityNodeInfo rootInfo = getRootInActiveWindow();
   if (rootInfo == null) {
    return;
   //開始遍歷,這里拎出來細講,直接往下看正文
   if (rootInfo.getChildCount() != 0) {
    ……
   }
  } catch (Exception e) {
  ztLog("Exception:" + e.getMessage(), true);
 }
}

拿到根節(jié)點以后,我們有兩種方式開始尋找目標節(jié)點:

  1. 根據(jù)View id:findAccessibilityNodeInfosByViewId
  2. 根據(jù)控件文案:findAccessibilityNodeInfosByText

這里我們拿魅族手機自帶的音樂App做例子,假如我們需要自動點擊下圖的 專欄 :

使用findAccessibilityNodeInfosByViewId尋找目標

我們可以使用findAccessibilityNodeInfosByViewId(),通過id找到目標節(jié)點,關于View id,可以使用DDMS中的Dump View Hierarchy for UI Automator,就是點擊下圖按鈕(不知道如何打開eclipse或者AS的DDMS的同學可以自行百度):

稍等片刻,生成屏幕快照,并解析出View樹,從右下的屬性框就可以找到id,同時仔細看,包名也可以獲取到啦~

這里很有可能因為目標apk混淆嚴重而讀不到id,比如是個?,那么可以嘗試第二個方法。

使用findAccessibilityNodeInfosByText尋找目標

使用findAccessibilityNodeInfosByText("最熱MV"),顧名思義,就是根據(jù)文案找控件。

找到控件以后,就可以執(zhí)行點擊操作了,但是且慢,這里有個坑。

因為注意看這里的view樹:

無論我們根據(jù)id還是文案,找到的可能只是一個TextView或者Button,但是根據(jù)我們?nèi)粘=?jīng)驗,我們肯定是給其父布局設置的點擊事件,也就是這里的LinearLayout或者FrameLayout。

所以我的方案是根據(jù)View樹的結構,自行遍歷。比如這里的View樹結構如下:

我先做深度優(yōu)先遍歷找到GridView,然后遍歷它所有孩子直至找到專欄這個TextView,為什么我不直接DFS找到專欄呢?因為我要記錄它的父節(jié)點甚至爺爺節(jié)點,方便接下來執(zhí)行點擊操作。

如果有同學使用這種方案,建議根據(jù)實際View樹的結構,自行遍歷尋找,我的代碼如下:

/**
 * 深度優(yōu)先遍歷尋找目標節(jié)點
 */
private void DFS(AccessibilityNodeInfo rootInfo) {
  if (rootInfo == null || TextUtils.isEmpty(rootInfo.getClassName())) {
    return;
  }
  if (!"android.widget.GridView".equals(rootInfo.getClassName())) {
    ztLog(rootInfo.getClassName().toString());
    for (int i = 0; i < rootInfo.getChildCount(); i++) {
      DFS(rootInfo.getChild(i));
    }
  } else {
    ztLog("==find gridView==");
    final AccessibilityNodeInfo GridViewInfo = rootInfo;
    for (int i = 0; i < GridViewInfo.getChildCount(); i++) {
      final AccessibilityNodeInfo frameLayoutInfo = GridViewInfo.getChild(i);
      //細心的同學會發(fā)現(xiàn),我代碼里的遍歷的邏輯跟View樹里顯示的結構不一樣,
      //快照顯示的FrameLayout下明明該是LinearLayout,我這里卻是TextView,
      //這個我也不知道,實際調(diào)試出來的就是這樣……所以大家實操過程中也要注意了
      final AccessibilityNodeInfo childInfo = frameLayoutInfo.getChild(0);
      String text = childInfo.getText().toString();
      if (text.equals("專欄")) {
        performClick(frameLayoutInfo);
      } else {
        ztLog(text);
      }
    }
  }
}

private void performClick(AccessibilityNodeInfo targetInfo) {
  targetInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}

AndroidManifest文件添加Service配置

AccessibilityService也是一個Servcie,所以要在AndroidManifest配置一下。

<service
  android:name=".AutoClickService"
  android:exported="false"
  <!-- label就是在手機設置中的無障礙里,顯示的標簽 -->
  android:label="自動點擊Demo"
  <!-- 注意這里的android:permission是在service結構里面的??! -->
  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/accessible_service_config" />
</service>

 至此無障礙模式方案就講完了,運行之后,需要在手機設置中的無障礙里打開對應的開關:

打開以后,自動點擊功能可以自動后臺運行了,不想用時可以在上圖開關那里關閉即可。

以后需要先運行App,再打開開關,開啟功能。

無障礙模式雖然用著挺舒服,但是在很多廠商的系統(tǒng)里,已經(jīng)打開的無障礙模式隔一段時間經(jīng)常會被自動關閉,比如MIUI系統(tǒng)里就要給App加開機運行的權限。

而廠商自帶的無障礙就沒事,猜測系統(tǒng)里內(nèi)置了處理,這也是無障礙模式的一個坑吧。

小結

最后總結一下,AccessibilityService是一個很有趣的功能,發(fā)揮想象力可以做很多事,但是要小心踩坑:

  1. 通過findAccessibilityNodeInfosByViewId或者findAccessibilityNodeInfosByText找到的目標控件不一定是你想要的點擊控件
  2. 各家廠商系統(tǒng)可能對無障礙模式內(nèi)置了屏蔽處理

adb shell命令

adb可以方便我們直接高效的操作真機,比如安裝apk,批量安裝apk,復制文件等,而模擬點擊事件也是可以通過adb命令完成的。

我是突然想到,前陣子看過網(wǎng)上流傳的一個“微信跳一跳”的輔助,使用python + adb完成。

原理就是adb負責截圖,python負責圖像識別像素計算距離,最后再由adb模擬點擊。

如果我們需要點擊的目標,坐標相對確定,那我們直接在代碼里執(zhí)行adb命令模擬點擊即可。

真機實驗

我們先用USB連接真機,在cmd命令行工具里:

adb shell
shell@PRO6:/ $ input tap 125 521
shell@PRO6:/ $ 

這里的意思就是點擊屏幕上 (x, y) = (125, 521)的地方。果然手機響應了,缺點就是響應時間略長,感覺有1秒左右。

同理其他手勢操作也可以完成,這里不作詳解,感興趣的可以自行搜索。

下面我們需要做的就是在代碼里完成上述操作,并且可以持續(xù)在后臺運行。這里我也是踩坑無數(shù),聽我慢慢吐槽。

尋找后臺執(zhí)行adb命令的方案

ProcessBuilder — OUT

沒什么好說的,直接看代碼:

  int x = 0, y = 0;
  String[] order = { "input", "tap", " ", x + "", y + "" };
  try {
    new ProcessBuilder(order).start();
  } catch (IOException e) {
    Log.i("GK", e.getMessage());
    e.printStackTrace();
  }

這種版本,在Activity中可行,但是切后臺不行……這肯定無法滿足需求,再找!

Instrumentation — OUT

try {
  Instrumentation inst = new Instrumentation();
  inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0));
  inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0));
  Log.i("GK", "模擬點擊" + x + ", " + y);
} catch (Exception e) {
  Log.e("Exception when sendPointerSync", e.toString());
}

這種版本和上一個一模一樣,不能后臺,差評!!

救世主Runtime登場

private OutputStream os;

/**
 * 執(zhí)行ADB命令: input tap 125 340
 */
private final void exec(String cmd) {
  try {
    if (os == null) {
      os = Runtime.getRuntime().exec("su").getOutputStream();
    }
    os.write(cmd.getBytes());
    os.flush();
  } catch (Exception e) {
    e.printStackTrace();
    Log.e("GK", e.getMessage());
  }
}

后臺問題迎刃而解!

添加合適的時機

目前我們把核心功能做完了,最后需要做的就是找到合適的時機,執(zhí)行操作。

首先我們的容器肯定是一個Service,然后后臺不斷的判斷當前app是否是目標app,如果是的話,再執(zhí)行自動點擊操作。

所以我們需要判斷當前前臺app的包名或者Activity的名字是否是我們的目標。

/**
 * 如果前臺APP是目標apk
 */
private boolean isCurrentAppIsTarget() {
  String name = getForegroundAppPackageName();
  if (!TextUtils.isEmpty(name) && PACKAGE_NAME.equalsIgnoreCase(name)) {
    return true;
  }
  return false;
}

/**
 * 獲取前臺程序包名
 */
public String getForegroundAppPackageName() {
  ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
  List<RunningAppProcessInfo> lr = am.getRunningAppProcesses();
  if (lr == null) {
    return null;
  }

  for (RunningAppProcessInfo ra : lr) {
    if (ra.importance == RunningAppProcessInfo.IMPORTANCE_VISIBLE || ra.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
      Log.i("GK", ra.processName);
      return ra.processName;
    }
  }
  return "";
}

以上就是adb shell方案,這種方案缺陷也比較明顯,就是要求 自動點擊的位置不能改變。

對于如何獲取點擊位置的坐標,可以打開開發(fā)者選項中的指針位置:

直接查看坐標。

總結

模擬點擊這種需求,我們一般都不會用到,也有點歪門邪道的意思。但是無論什么需求,中間的探索過程才最珍貴。技術也是人,不是每次都會有說干就干的決心和勇氣,保持一顆好奇心,珍惜每次探索的機會,學有所得,小有收獲,也未嘗不是一種自我認可。

最后附上源碼:AutoClickService

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Android用文件存儲數(shù)據(jù)的方法

    Android用文件存儲數(shù)據(jù)的方法

    這篇文章主要為大家詳細介紹了Android用文件存儲數(shù)據(jù)的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Flutter實現(xiàn)微信朋友圈功能

    Flutter實現(xiàn)微信朋友圈功能

    這篇文章主要為大家詳細介紹了Flutter實現(xiàn)微信朋友圈功,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Android?線程死鎖場景與優(yōu)化解決

    Android?線程死鎖場景與優(yōu)化解決

    線程死鎖是老生常談的問題,線程池死鎖本質(zhì)上屬于線程死鎖的一部分,線程池造成的死鎖問題往往和業(yè)務場景相關,本文主要介紹了Android?線程死鎖場景與優(yōu)化,感興趣的可以了解一下
    2023-12-12
  • Android開發(fā)實現(xiàn)的圖片瀏覽功能示例【放大圖片】

    Android開發(fā)實現(xiàn)的圖片瀏覽功能示例【放大圖片】

    這篇文章主要介紹了Android開發(fā)實現(xiàn)的圖片瀏覽功能,結合實例形式分析了Android針對圖片的切換顯示、透明度、大小調(diào)整等相關操作技巧,需要的朋友可以參考下
    2019-04-04
  • Android xUtils更新到3.0后的基本使用規(guī)則詳解

    Android xUtils更新到3.0后的基本使用規(guī)則詳解

    xUtils是基于android的開發(fā)框架,簡化了很多的開發(fā)步驟,可以說是非常好的開發(fā)工具。下面小編給大家?guī)砹薃ndroid xUtils更新到3.0后的基本使用規(guī)則詳解,感興趣的朋友一起學習吧
    2016-08-08
  • React-Native  Android 與 IOS App使用一份代碼實現(xiàn)方法

    React-Native Android 與 IOS App使用一份代碼實現(xiàn)方法

    這篇文章主要介紹了React-Native Android 與 IOS App使用一份代碼實現(xiàn)方法的相關資料,這里舉例說明,該如何實現(xiàn)IOS和Android APP 都使用一樣的代碼,需要的朋友可以參考下
    2016-12-12
  • Android程序開發(fā)之給背景圖加上移動的手勢

    Android程序開發(fā)之給背景圖加上移動的手勢

    這篇文章主要介紹了Android程序開發(fā)之給背景圖加上移動的手勢 的相關資料,需要的朋友可以參考下
    2016-03-03
  • 淺談Glide緩存key的問題

    淺談Glide緩存key的問題

    這篇文章主要介紹了淺談Glide緩存key的問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式

    Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式

    本篇文章主要介紹Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Android條目拖拽刪除功能實例代碼

    Android條目拖拽刪除功能實例代碼

    最近做項目遇到這樣的需求,要做條目條目拖拽刪除效果,實際效果和QQ消息刪除一樣,側滑有制定和刪除,下面通過本文給大家分享Android條目拖拽刪除功能,需要的朋友參考下吧
    2017-08-08

最新評論

万盛区| 湘阴县| 大竹县| 吉安市| 兴仁县| 顺义区| 阿荣旗| 荥阳市| 龙川县| 嘉黎县| 陕西省| 郯城县| 昭通市| 铁岭县| 蒙城县| 通榆县| 兴隆县| 大城县| 镇安县| 封丘县| 南乐县| 南开区| 新邵县| 长葛市| 卢龙县| 新化县| 玉屏| 张家川| 六盘水市| 白银市| 社旗县| 双城市| 梅州市| 宿州市| 潍坊市| 古浪县| 昌图县| 日照市| 沁源县| 湖口县| 新邵县|