日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

无障碍服务(AccessibilityService)

發布時間:2023/12/20 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无障碍服务(AccessibilityService) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用步驟

  • 實現一個繼承自 AccessibilityService 的服務類。
  • 設定配置信息,以便系統知道該輔助模式的一些基本信息,例如監聽那些事件。
  • 在清單文件(AndroidManifest.xml)中,注冊此服務。
  • 在系統設置中,找到“無障礙”,并開啟此服務。
  • 1 繼承 AccessibilityService

  • public abstract void onAccessibilityEvent(AccessibilityEvent event);//監聽的事件發生回調
  • public abstract void onInterrupt();//系統事件被打斷回調
  • 2 配置輔助模式

    配置 AccessibilityService 有兩種方式,

    • 通過 xml 配置文件
    <accessibility-servicexmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackAllMask"android:accessibilityFlags="flagReportViewIds"android:canRetrieveWindowContent="true"android:packageNames="com.forwarding.wechat"android:description="@string/accessbility_desc"android:notificationTimeout="100" />

    accessibilityEventTypes:監聽的事件類型,例如:typeAllMask 表示全部事件,而 typeViewClicked 表示只監聽點擊事件。
    accessibilityFeedbackType:監聽事件的反饋模式。
    canRetrieveWindowContent:是否允許獲取視圖層級的訪問權,如果它被設置為 false,node.getSource() 方法會調用失敗。
    accessibilityFlags:指定 Flag,一般用于指定根據 Node 獲取 View ID 的權限。
    packageNames:開啟監聽的應用包名,可以指定多個包名,通過逗號“,”分割,不設置此屬性標識全局監聽。
    description:輔助功能的描述,它會顯示在系統設置的“無障礙”中的描述信息中。
    notificationTimeout:響應的毫秒數。

    更多配置參數:https://developer.android.com/reference/android/accessibilityservice/AccessibilityService

    • 通過 Java 代碼中動態配置。
      重寫 AccessibilityService 的 onServiceConnected() 方法(不推薦)

    3 清單文件中注冊服務

    <service android:label="無障礙名"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"android:name=".WeForwardServer"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService"/></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility_config"/> </service>

    4 開啟輔助模式

    默認為關閉狀態,打開它的時候,你會收到一個警告彈窗,說明當前你正在開啟一個無障礙的服務

    編寫邏輯代碼

    1 判斷事件

    • eventType 判斷事件類型(通過 eventType 來判斷事件的類型,我們可以利用 getEventType() 方法獲取到它。)
    • packageName 判斷事件發生的 App(通過 getPackageName() 方法,判斷出事件發生在那個 App 里的。)
    • className 判斷當前發生事件的是那個類(通過 getClassName() 判斷當前發生事件的是那個類)
    • text 判斷當前事件觸發源上的 Text(通過 getText() 獲取當前事件源的 text 屬性,可能是 TextView 的 Text,也可能是 Activity 的 Label 屬性)

    2 找到待控制的關鍵節點(Node)

    通常我們是使用輔助模式去操作頁面上的某個元素,那這一步,就是為了找到它。

    在輔助模式下,頁面上的每個元素,其實都是一個個 AccessibilityNodeInfo 節點,它是一個類似樹形的結構,其內和我們真實 App 內的布局層級是一致的,但是并不能將它單純的理解成一個 ViewTree。

    既然是樹形結構,我們首先要獲取到根節點的 NodeInfo,可以通過以下兩個方式獲取:

    event.getSource() getRootInActiveWindow()

    這兩個方法都會返回一個 AccessibilityNodeInfo 對象。getSource() 是AccessibilityEvent 的方法,它可用的前提是前面配置 android:canRetrieveWindowContent 的時候,被設置為 True。所以我推薦使用 getRootInActiveWindow() 方法來獲取。這兩個方法還是略微有些差異,有興趣可以打斷點看看信息,但是大多數情況下,對我們使用者來說是一致的。

    獲得根節點的 AccessibilityNodeInfo 之后,就可以通過它找到我們想操作的關鍵節點,在 AccessibilityNodeInfo 中,提供了以下兩個方法來找到關鍵節點。

    findAccessibilityNodeInfosByViewId(String viewId) findAccessibilityNodeInfosByText(String text)

    一個是依賴 ViewId,另外一個是依賴 Text 信息。

    使用 ViewId 查找關鍵節點是穩妥的方案,而使用 Text 去查找,可能會找不到。

    無論通過哪種方式查找 關鍵節點 ,都是存在能找到多個 NodeInfo 的可能的,所以這兩個方法干脆的都返回了一個 List ,所以需要我們通過其他條件再過濾一遍,通常就是通過 Text 信息過濾。

    var mNodeInfo = rootInActiveWindow var listItem = mNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/lp") for (item in listItem) {if (item.text.toString().equals("承香墨影")){nodeClick(item)} }

    如果是使用 findXxxByText() 的方法的話,還需要注意它實際上不是通過類似 == 或者 equals() 的方法來查找子節點的,而是通過類似 contain() 的方式,所以只要節點的 text 屬性包含查找的內容,都會被找到,這個我們額外還需要增加判斷條件。

    如果這些方法都試過,還是找不到關鍵節點,可以通過遍歷的方式查找。

    AccessibilityNodeInfo 既然是一個樹狀結構,也提供了我們遍歷樹的方法。

    getParent():查找父節點。
    getChild():返回子節點。
    getChildCount():當前節點的子節點個數。
    通過 getChild() 和 getChildCount() 兩個方法,我們是可以對整個 ViewNodeTree 進行遍歷,來找到我們關注的關鍵節點,這是一個最后的方案,并不推薦使用。

    3 觸發事件

    輔助模式一般都是幫助我們響應一些事件,而這些事件大體上,可以分為兩類。

    • 全局系統事件。
      對于全局系統事件,其實我們并不需要第二步找到的關鍵節點。AccessibilityService 提供了一個 performGlobalAction() 方法,我們可以通過該方法,操作一些全局的系統事件,例如:模擬返回鍵點擊、模擬 HOME 鍵點擊、鎖屏等等。
    // 返回鍵 performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); // HOME鍵 performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);

    除了全局系統事件之外,通常我們就是想操作第二步拿到的關鍵節點。

    在 AccessibilityNodeInfo 中,提供了一個 performAction() 的方法,可以通過該方法,對關鍵節點傳遞一個我們需要的事件。

    這些事件都被定義在 AccessibilityNodeInfo 中,以 ACTION_ 為前綴定義。例如:ACTION_CLICK 是一個點擊事件,ACTION_SET_TEXT 設置一個輸入。

    這里僅介紹一些比較常見的操作,更多的操作也是類似的使用方式。

    • View 事件。
      找到關鍵節點之后,就可以發送 AccessibilityNodeInfo.ACTION_CLICK 模擬對這個 View 的點擊操作。
  • EditText 輸入文字
    對 EditText 輸入文字,最少需要兩個參數,關鍵節點和輸入的文字。這就需要用到 performAction() 的另外一個重載方法,它允許額外在傳遞一個 Bundle 來指定參數。
  • private fun nodeSetText(node : AccessibilityNodeInfo?,text:String){var argument = Bundle()argument.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,text)node?.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT,argument) }

    所有支持定義的額外參數,都被定義在 AccessibilityNodeInfo 中,并以 ACTION_ARGUMENT_ 為前綴定義。
    3. ListView 的滾動
    AccessibilityNodeInfo 其實只能操作當前屏幕下可見的 節點,所以碰上 ListView 或者 RecycleView 這種列表,就需要對它進行滾動。

    滾動的事件有兩種:

    • ACTION_SCROLL_FORWARD
    • ACTION_SCROLL_BACKWARD
    private fun nodeScrollList(node : AccessibilityNodeInfo?){node?.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) }

    一個前進一個后退,足夠使用了。

    4 回收資源

    nodeInfo.recycle();

    總結

    以上是生活随笔為你收集整理的无障碍服务(AccessibilityService)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。