Android 無(wú)障礙開(kāi)發(fā)入門

一桂敛、AccessibilityService

根據(jù)官方的介紹,是指開(kāi)發(fā)者通過(guò)增加類似contentDescription的屬性溅潜,從而在不修改代碼的情況下术唬,讓殘障人士能夠獲得使用體驗(yàn)的優(yōu)化,大家可以打開(kāi)AccessibilityService來(lái)試一下滚澜,點(diǎn)擊區(qū)域粗仓,可以有語(yǔ)音或者觸摸的提示,幫助殘障人士更好的使用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 開(kāi)發(fā)流程

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

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

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

3.編寫腳本代碼

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

三召噩、核心代碼

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

public class AccessibilitySampleService extends AccessibilityService{

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

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

       AccessibilityOperator.getInstance().updateEvent(this, event);
       //過(guò)濾出目標(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ú)障礙服務(wù)斷開(kāi)后回調(diào)*/
   @Override 
   public void onInterrupt(){
       // TODO Auto-generated method stub 
   }
}

方法說(shuō)明

1. onServiceConnected

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

也可以通過(guò)

android.accessibilityservice.AccessibilityService#getServiceInfo

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

2. onAccessibilityEvent

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

可以用

android.view.accessibility.AccessibilityRecord#getSource

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

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

3. onInterrupt

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

4. AccessibilityService 其他方法說(shuō)明

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

更多AccessibilityService參數(shù)說(shuō)明見(jiàn)官方文檔:

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

AccessibilityEvent

字段名 字段說(shuō)明
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>
           <!--       通過(guò)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說(shuō)明

官方文檔說(shuō)明:

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

這里列舉一些比較常用的

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

方法名 方法說(shuō)明
findAccessibilityNodeInfosByText() 通過(guò)字符串查找節(jié)點(diǎn)元素
findAccessibilityNodeInfosByViewId() 通過(guò)視圖id查找節(jié)點(diǎn)元素
performAction() 在節(jié)點(diǎn)上執(zhí)行一個(gè)動(dòng)作,比如點(diǎn)擊杂数、向上滑動(dòng)等宛畦,更多操作見(jiàn)下面的官方文檔
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)系作者
  • 序言:七十年代末次和,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子那伐,更是在濱河造成了極大的恐慌斯够,老刑警劉巖囚玫,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異读规,居然都是意外死亡抓督,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門束亏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)铃在,“玉大人,你說(shuō)我怎么就攤上這事碍遍《ㄍ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵怕敬,是天一觀的道長(zhǎng)揣炕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)东跪,這世上最難降的妖魔是什么畸陡? 我笑而不...
    開(kāi)封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮虽填,結(jié)果婚禮上丁恭,老公的妹妹穿的比我還像新娘。我一直安慰自己斋日,他們只是感情好牲览,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著恶守,像睡著了一般第献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兔港,一...
    開(kāi)封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天痊硕,我揣著相機(jī)與錄音,去河邊找鬼押框。 笑死岔绸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的橡伞。 我是一名探鬼主播盒揉,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兑徘!你這毒婦竟也來(lái)了刚盈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挂脑,失蹤者是張志新(化名)和其女友劉穎藕漱,沒(méi)想到半個(gè)月后欲侮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肋联,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年威蕉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橄仍。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡韧涨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侮繁,到底是詐尸還是另有隱情虑粥,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布宪哩,位于F島的核電站娩贷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏锁孟。R本人自食惡果不足惜彬祖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罗岖。 院中可真熱鬧,春花似錦腹躁、人聲如沸桑包。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哑了。三九已至,卻和暖如春烧颖,著一層夾襖步出監(jiān)牢的瞬間弱左,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工炕淮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拆火,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓涂圆,卻偏偏與公主長(zhǎng)得像们镜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子润歉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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