Android 無障礙開發(fā)入門

一、AccessibilityService

根據(jù)官方的介紹,是指開發(fā)者通過增加類似contentDescription的屬性,從而在不修改代碼的情況下,讓殘障人士能夠獲得使用體驗(yàn)的優(yōu)化,大家可以打開AccessibilityService來試一下,點(diǎn)擊區(qū)域,可以有語音或者觸摸的提示,幫助殘障人士更好的使用App

現(xiàn)在被廣泛應(yīng)用在自動(dòng)化,比如自動(dòng)搶紅包,抖音自動(dòng)關(guān)注點(diǎn)贊等

官方文檔:

https://developer.android.com/guide/topics/ui/accessibility/service

二、AccessibilityService 開發(fā)流程

1.確定執(zhí)行腳本的APK安裝包

2.通過UIAutomator 獲取包名及UI控件ID,或者下載一個(gè)開發(fā)者助手apk,也可以進(jìn)行控件ID獲取,代碼君已經(jīng)幫你下載好了,需要自取

http://share.dmjzy.cn/f/17143538-501591536-a374b2(訪問密碼:8401

3.編寫腳本代碼

4.調(diào)試、兼容性處理

三、核心代碼

1.AccessibilityService主要是實(shí)現(xiàn)onAccessibilityEvent

public class AccessibilitySampleService extends AccessibilityService{

    /**當(dāng)無障礙服務(wù)連接之后回調(diào)*/
   @Override
   public void  onServiceConnected() {
        super.onServiceConnected()
    }

    /**當(dāng)觸發(fā)了需要監(jiān)聽的無障礙事件后回調(diào)*/
   @Override 
   public void onAccessibilityEvent(AccessibilityEvent event){
       // 獲取包名
       String pkgName = event.getPackageName().toString();
       int eventType = event.getEventType();

       AccessibilityOperator.getInstance().updateEvent(this, event);
       //過濾出目標(biāo)包,如果要檢測(cè)所有包,可以去掉此判斷
       if (pkgName.equals(pageName)) {
           AccessibilityLog.printLog("eventType: " + eventType + " pkgName: " + pkgName);

           switch (eventType) {
               case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                   //執(zhí)行具體的腳本
                   toOperator();
                   break;
               case AccessibilityEvent.TYPE_VIEW_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                   break;
           }
       }
   } 
   /**無障礙服務(wù)斷開后回調(diào)*/
   @Override 
   public void onInterrupt(){
       // TODO Auto-generated method stub 
   }
}

方法說明

1. onServiceConnected

當(dāng)聲明的無障礙服務(wù)連接之后, 系統(tǒng)會(huì)回調(diào)此方法. 在這個(gè)方法里, 可以做一些初始化工作. 比如保存服務(wù)的實(shí)例 標(biāo)識(shí)服務(wù)連接的狀態(tài)等.

也可以通過

android.accessibilityservice.AccessibilityService#getServiceInfo

動(dòng)態(tài)更改xml配置文件中聲明的無障礙配置信息.

2. onAccessibilityEvent

當(dāng)監(jiān)聽的事件觸發(fā)時(shí), 系統(tǒng)會(huì)回調(diào)此方法, 比如view被點(diǎn)擊了 window內(nèi)容改變了等.

可以用

android.view.accessibility.AccessibilityRecord#getSource

獲取對(duì)象AccessibilityNodeInfo, 這個(gè)對(duì)象就是無障礙操作的核心對(duì)象, 通常可以理解為android開發(fā)中的view控件.

可以通過AccessibilityNodeInfo對(duì)象, 進(jìn)行控件的點(diǎn)擊操作 輸入文本操作 滾動(dòng)操作 獲取文本操作等

3. onInterrupt

當(dāng)中途關(guān)閉了無障礙服務(wù)時(shí)回調(diào), 通常這個(gè)時(shí)候無障礙服務(wù)不可用, 調(diào)用api都會(huì)失敗.

4. AccessibilityService 其他方法說明

方法名 方法說明
disableSelf() 禁用當(dāng)前服務(wù),也就是在服務(wù)可以通過該方法停止運(yùn)行
findFoucs(int falg) 查找擁有特定焦點(diǎn)類型的控件
getRootInActiveWindow() 如果配置能夠獲取窗口內(nèi)容,則會(huì)返回當(dāng)前活動(dòng)窗口的根結(jié)點(diǎn)
performGlobalAction(int action) 執(zhí)行全局操作,比如返回,回到主頁,打開最近等操作,此方法可以模擬用戶點(diǎn)擊返回鍵和home鍵,操作見下面的官方文檔
setServiceInfo(AccessibilityServiceInfo info) 設(shè)置當(dāng)前服務(wù)的配置信息
getSystemService(String name) 獲取系統(tǒng)服務(wù)
onKeyEvent(KeyEvent event) 如果允許服務(wù)監(jiān)聽按鍵操作,該方法是按鍵事件的回調(diào),需要注意,這個(gè)過程發(fā)生了系統(tǒng)處理按鍵事件之前

更多AccessibilityService參數(shù)說明見官方文檔:

https://developer.android.google.cn/reference/kotlin/android/accessibilityservice/AccessibilityService

AccessibilityEvent

字段名 字段說明
TYPE_NOTIFICATION_STATE_CHANGED 通知欄狀態(tài)變化
TYPE_VIEW_CLICKED 視圖被點(diǎn)擊
TYPE_WINDOW_CONTENT_CHANGED 窗口內(nèi)容變化
TYPE_WINDOW_STATE_CHANGED 窗口狀態(tài)變化,即切換activity

2. AndroidManifest.xml注冊(cè)服務(wù)

<!-- 注冊(cè)輔助功能服務(wù)-->
       <service
           android:name=".AccessibilitySampleService"
           android:exported="true"
           android:label="碼君助手"
           android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
           android:process=":BackgroundService">
           <intent-filter>
               <action android:name="android.accessibilityservice.AccessibilityService" />
           </intent-filter>
           <!--       通過xml文件完成輔助功能相關(guān)配置,也可以在onServiceConnected中動(dòng)態(tài)配置-->
           <meta-data
               android:name="android.accessibilityservice"
               android:resource="@xml/accessibility_config" />
       </service>

3. 在資源文件夾新增xml文件夾,新建accessibility_config文件,代碼如下

<?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:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:description="@string/accessibility_desc"
    android:notificationTimeout="10" />

<!--  canPerformGestures  //申請(qǐng)手勢(shì)權(quán)限-->
<!--accessibility_desc:碼君助手,讓你的手機(jī)更智能一點(diǎn) -->

accessibility_config說明

官方文檔說明:

https://developer.android.google.cn/reference/android/R.styleable#AccessibilityService

這里列舉一些比較常用的

字段名 字段說明
accessibilityEventTypes 表示該服務(wù)對(duì)界面中的哪些變化感興趣,即哪些事件通知,比如窗口打開,滑動(dòng),焦點(diǎn)變化,長(zhǎng)按等.具體的值可以在AccessibilityEvent類中查到,如typeAllMask表示接受所有的事件通知
accessibilityFeedbackType 表示反饋方式,比如是語音播放,還是震動(dòng)。feedbackGeneric代表所有
canRetrieveWindowContent 表示該服務(wù)能否訪問活動(dòng)窗口中的內(nèi)容.也就是如果你希望在服務(wù)中獲取窗體內(nèi)容的化,則需要設(shè)置其值為true
notificationTimeout 接受事件的時(shí)間間隔,通常將其設(shè)置為100即可
packageNames 表示對(duì)該服務(wù)是用來監(jiān)聽哪個(gè)包的產(chǎn)生的事件。如果不寫代表監(jiān)聽所有的應(yīng)用。中間可以用";"來分割。
canPerformGestures 表示可以執(zhí)行手勢(shì)屬性
canTakeScreenshot 是否能夠截屏

4、編寫執(zhí)行腳本

try {
           Thread.sleep(2000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/btn_later");// 關(guān)閉彈框

           Thread.sleep(1000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/tab_work");//切換到工作tab
           AccessibilityLog.printLog("切換到工作tab: ");

       } catch (InterruptedException e) {
           e.printStackTrace();
       }

AccessibilityNodeInfo

方法名 方法說明
findAccessibilityNodeInfosByText() 通過字符串查找節(jié)點(diǎn)元素
findAccessibilityNodeInfosByViewId() 通過視圖id查找節(jié)點(diǎn)元素
performAction() 在節(jié)點(diǎn)上執(zhí)行一個(gè)動(dòng)作,比如點(diǎn)擊、向上滑動(dòng)等,更多操作見下面的官方文檔
getParent() 獲取父節(jié)點(diǎn)
getChild() 獲取子節(jié)點(diǎn)
isEnabled() 判斷節(jié)點(diǎn)是否激活
isClickable() 判斷節(jié)點(diǎn)是否可以點(diǎn)擊
isScrollable() 判斷節(jié)點(diǎn)是否可以滾動(dòng)
isSelected() 判斷節(jié)點(diǎn)是否選中
isPassword() 判斷節(jié)點(diǎn)是否是密碼輸入框
isFocusable() 判斷節(jié)點(diǎn)是否可以獲取焦點(diǎn)
getText() 獲取節(jié)點(diǎn)的文本信息
getContentDescription() 節(jié)點(diǎn)的內(nèi)容描述
getViewIdResourceName() 獲取節(jié)點(diǎn)控件的id ,獲取到的值大概是這樣的:com.ss.android.ugc.aweme:id/afy
getBoundsInScreen() 獲取節(jié)點(diǎn)在屏幕中的位置
getClassName() 獲取節(jié)點(diǎn)的類型/類名,值:android.widget.LinearLayout
getChild() 獲取子節(jié)點(diǎn)的AccessibilityNodeInfo信息

更多請(qǐng)查看官方文檔:

https://developer.android.google.cn/reference/android/view/accessibility/AccessibilityNodeInfo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容