詳解安卓輔助功能服務(wù)AccessibilityService(無(wú)障礙服務(wù)愕秫,微信搶紅包助手原理)

前言

在手機(jī)的更多設(shè)置或者高級(jí)設(shè)置中,我們會(huì)發(fā)現(xiàn)有個(gè)無(wú)障礙的功能焰络,很多人不知道這個(gè)功能具體是干嘛的戴甩,包括我們開發(fā)也很少接觸這部分功能,以至于對(duì)這塊不甚了解闪彼。前段時(shí)間在同事的安利下去了解了下這部分功能甜孤。在這里和大家淺談下自己對(duì)這個(gè)功能的理解和部分運(yùn)用。這邊打算從 “是什么畏腕,為什么缴川,怎么用,好不好”幾個(gè)方面來(lái)說(shuō)

提綱

是什么(應(yīng)用場(chǎng)景描馅,定義把夸,作用)

為什么(原理及源碼解析)

怎么用(如何開發(fā)無(wú)障礙服務(wù))

怎么防(防止無(wú)障礙服務(wù)外掛的一些做法)

是什么(定位及作用)

為了更好的介紹輔助功能服務(wù),這里先看下應(yīng)用場(chǎng)景

輔助功能服務(wù)一般用于操作自動(dòng)化和輔助操作

應(yīng)用場(chǎng)景

●?操作自動(dòng)化铭污,通過(guò)輔助功能服務(wù)來(lái)代替用戶執(zhí)行連續(xù)性的操作恋日,重復(fù)性的操作膀篮,或者特殊場(chǎng)景的操作(例如自動(dòng)搶紅包,自動(dòng)點(diǎn)贊岂膳,自動(dòng)回復(fù)誓竿,自動(dòng)搜索更優(yōu)惠商品)

WechatHelper? ?https://github.com/coder-pig/WechatHelper

●?輔助操作,幫助無(wú)法和設(shè)備完全交互的用戶(例如患有視力問(wèn)題或正在忙而無(wú)法操作手機(jī)的用戶)執(zhí)行操作(例如talkback(視力低弱輔助)谈截,隨選聽讀筷屡,語(yǔ)音操作)

官方定義(AccessibilityService)

無(wú)障礙服務(wù)是一種應(yīng)用程序,給有殘疾的用戶或暫時(shí)無(wú)法與設(shè)備完全交互的用戶提供了更好的無(wú)障礙用戶交互功能傻盟。比如駕駛速蕊、照顧小孩或者在吵鬧的派對(duì)上可能需要額外或者替代的交互反饋嫂丙。

Android提供標(biāo)準(zhǔn)的輔助功能服務(wù)娘赴,包括TalkBack,開發(fā)人員可以創(chuàng)建和分發(fā)自己的服務(wù)跟啤。

引入及發(fā)展

在Android 4.0以前诽表,Accessibility功能單一,僅能過(guò)單向獲取窗口信息(獲取輸入框內(nèi)容)隅肥;

在Android 4.0及以后竿奏,Accessibility增加了與窗口元素的雙向交互,可以操作窗口元素(點(diǎn)擊按鈕)腥放。

在Android 4.0之前泛啸,無(wú)障礙服務(wù)事件在提供有關(guān)用戶選擇的用戶界面控件的信息時(shí),只提供了有限的上下文信息秃症。在許多情況下候址,缺少的上下文信息可能對(duì)理解所選控件的含義至關(guān)重要。

Android 4.0通過(guò)基于視圖層次結(jié)構(gòu)組合可訪問(wèn)性事件种柑,顯著擴(kuò)展了輔助功能服務(wù)可以獲得的有關(guān)用戶界面交互的信息量岗仑。

輔助功能服務(wù)可以代表用戶執(zhí)行操作,包括更改輸入焦點(diǎn)和選擇(激活)用戶界面元素聚请。在Android

4.1(API級(jí)別16)中荠雕,操作范圍已擴(kuò)展為包括滾動(dòng)列表和與文本字段交互。

輔助功能服務(wù)的作用

因?yàn)闊o(wú)障礙服務(wù)具有強(qiáng)大的界面監(jiān)聽能力和替代用戶操作的能力驶赏,谷歌建議輔助功能服務(wù)僅應(yīng)用于幫助殘障用戶使用Android設(shè)備和應(yīng)用炸卑。

在我們開發(fā)者看來(lái),無(wú)障礙服務(wù)顯然能做的更多煤傍,例如微信搶紅包應(yīng)用盖文,自動(dòng)點(diǎn)贊,自動(dòng)回復(fù)等

android 輔助功能google官方示例?https://github.com/googlesamples/android-BasicAccessibility

為什么(原理及源碼解析)

Q:為什么輔助功能可以監(jiān)聽用戶的操作患久,界面變化椅寺,并根據(jù)需要進(jìn)行反饋

A:輔助功能通過(guò)在后臺(tái)中運(yùn)行無(wú)障礙服務(wù)浑槽,通過(guò)AccessibilityEvent接收指定事件的回調(diào),這樣的事件表示用戶在界面中的一些狀態(tài)轉(zhuǎn)換返帕,例如:焦點(diǎn)改變了桐玻,一個(gè)按鈕被點(diǎn)擊,等等荆萤。

簡(jiǎn)單的說(shuō)無(wú)障礙就是一個(gè)后臺(tái)監(jiān)控服務(wù)镊靴,當(dāng)你監(jiān)控的內(nèi)容發(fā)生改變時(shí),就會(huì)調(diào)用后臺(tái)服務(wù)的回調(diào)方法

從具體實(shí)例入手看原理:程序內(nèi)部的后臺(tái)服務(wù)——?內(nèi)部的跨進(jìn)程通信 AM & AMS

拿一個(gè)具體的例子來(lái)看链韭,這是一個(gè)搶紅包的外掛偏竟,把WeChat稱作Target

APP,就是被監(jiān)控的APP敞峭,當(dāng)跳出來(lái)一個(gè)紅包踊谋,觸發(fā)了一個(gè)AccessibilityEvent,system_server中的AccessibilityManagerService將AccessibilityEvent分發(fā)給有AccessibilityService的APP旋讹,稱為Accessibility

APP殖蚕,這個(gè)AccessibilityService受到這個(gè)AccessibilityEvent后,會(huì)找到這個(gè)頁(yè)面的Open

Button沉迹,模擬點(diǎn)擊睦疫。


而在程序內(nèi)部,這個(gè)過(guò)程其實(shí)就是三個(gè)類之間的交互 AccessibilityManager(AM):發(fā)送AccessibilityEventAccessibilityManagerService(AMS):分發(fā)事件AccessibilityService(AS):進(jìn)行回應(yīng)?

看到AccessibilityManagerService這樣的起名鞭呕,就很容易聯(lián)想到蛤育,這是一個(gè)Binder通信的過(guò)程,AM通過(guò)IAccessibilityManager(AMS的本地Binder)與AMS跨進(jìn)程通信葫松。AMS通過(guò)IAccessibilityManagerClient(AM的本地Binder)與AM通信瓦糕。

AM是與AMS進(jìn)行通信

AM是什么時(shí)候與AMS進(jìn)行通信的,查看源碼可以知道进宝,AM的設(shè)計(jì)其實(shí)是一個(gè)單例模式刻坊,每個(gè)app進(jìn)程都會(huì)有一個(gè)AM,而AM在構(gòu)建的時(shí)候党晋,即getInstance的時(shí)候谭胚,就會(huì)調(diào)用tryConnectToServiceLocked()的方法,連接AMS未玻,得到AMS的代理后灾而,把自己的代理也設(shè)置給AMS,這樣AM就可以和AMS進(jìn)行通信了


AS和AMS聯(lián)系的時(shí)機(jī)

那么AS又是什么時(shí)候和AMS有聯(lián)系的呢扳剿,這又是一個(gè)跨進(jìn)程binder通信的過(guò)程旁趟。

無(wú)障礙服務(wù)是很強(qiáng)大的服務(wù),需要我們進(jìn)到設(shè)置中開啟這個(gè)服務(wù)庇绽。綁定Service锡搜。

這里我們結(jié)合時(shí)序圖進(jìn)行說(shuō)明橙困。

Settings->Accessibility->enable(enableAccessibilityServiceLocked())

Settings->Accessibility->disable(disableAccessibilityServiceLocked())

Some RegisterBroadcastReceivers (registerBroadcastReceivers())

當(dāng)用戶在設(shè)置->無(wú)障礙里面選擇了開啟或關(guān)閉一個(gè)輔助功能,會(huì)導(dǎo)致一些系統(tǒng)狀態(tài)會(huì)變化耕餐;Accessibility APP的安裝狀態(tài)會(huì)以BroadcastReceivers的方式會(huì)通知狀態(tài)改變凡傅;還有其他的一些狀態(tài)改變。這些變化最終會(huì)調(diào)用到AMS的onUserStateChangedLocked()方法肠缔。

RegisterBroadcastReceivers? 很多情況簡(jiǎn)單列為這四種夏跷,安裝app,更新app明未。強(qiáng)制關(guān)閉app槽华,刪除app。

onUserStateChangedLocked方法中趟妥,有比較多的方法調(diào)用猫态,都是一些特定狀態(tài)的更新,但我們這次只用關(guān)注updateServicesLocked這個(gè)方法煮纵,是處理無(wú)障礙服務(wù)綁定的

updateServicesLocked這個(gè)方法涉及到多個(gè)AMS類內(nèi)部的集合懂鸵,遍歷如上圖左邊所見

這個(gè)方法會(huì)遍歷ams中的mInstalledServices偏螺,看名字可以知道是已經(jīng)安裝的無(wú)障礙服務(wù)列表行疏。

然后根據(jù)enableServices,判斷是否已經(jīng)啟用套像,如果啟用則通過(guò)mComponentNameToServiceMap判斷是否為空酿联,為空就會(huì)new一個(gè)AccessibilityServiceConnection, 調(diào)用其bindlock方法夺巩,綁定

未啟用就通過(guò)mComponentNameToServiceMap判斷是否為空贞让,不為空就調(diào)用其unbindLocked(),解綁

接下來(lái)的過(guò)程其實(shí)就是跨進(jìn)程的Binder通信柳譬。AS會(huì)通過(guò)onBind(Intent intent)這個(gè)函數(shù)返回一個(gè)IAccessibilityServiceClientWrapper對(duì)象給AccessibilityServiceConnection喳张,這個(gè)對(duì)象就是AS的本地Binder,AccessibilityServiceConnection通過(guò)這個(gè)本地Binder去和AS通信美澳。

然后AccessibilityServiceConnection會(huì)在onServiceConnected中調(diào)用方法销部,把自己的代理傳到AS中。

監(jiān)聽無(wú)障礙服務(wù)事件(觸發(fā) 分發(fā) 回調(diào))

講完服務(wù)是什么時(shí)候綁定的制跟,怎么建立通信的舅桩。接下來(lái)說(shuō)下怎么監(jiān)聽事件的,AccessibilityEvent 是從哪里傳遞出來(lái)的

這里分為觸發(fā) 分發(fā) 回調(diào)三個(gè)部分

先說(shuō)觸發(fā)雨膨,以點(diǎn)擊為例

首先需要知道View都有接入 AccessibilityEventSource接口 分有兩個(gè)方法擂涛。用于發(fā)送無(wú)障礙事件。

回歸到圖的部分

●?View.java -- performClick() 被點(diǎn)擊調(diào)用

●?View.java -- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 發(fā)送類型為click的事件

●?View.java -- sendAccessibilityEventInternal() 創(chuàng)建了一個(gè)AM的實(shí)例(app單例)聊记,判斷是否enable狀態(tài),創(chuàng)建AM實(shí)例時(shí)會(huì)通過(guò)binder綁定遠(yuǎn)程AMS

●?View.java -- sendAccessibilityEventUnchecked(AccessibilityEvent) 這個(gè)Event方法是根據(jù)type調(diào)用AccessibilityEvent.obtain(type)創(chuàng)建的

●?View.java -- sendAccessibilityEventUncheckedInternal() 會(huì)調(diào)用onInitializeAccessibilityEvent()初始化一些event信息撒妈,比如className/packageName/source等恢暖,然后會(huì)調(diào)用getParent().requestSendAccessibilityEvent(this,event)將event分發(fā)給ParentView。requestSendAccessibilityEvent會(huì)不斷往上調(diào)用getParent().requestSendAccessibilityEvent(this,event),ViewRootImpl.requestSendAccessibilityEvent不管ParentView是哪一個(gè)狰右,最終會(huì)到View層次中的頂層胀茵,也就是ViewRootImpl

●?ViewRootImpl?-- requestSendAccessibilityEvent() 在這里就會(huì)調(diào)用AccessibilityManager.sendAccessibilityEvent(event);

●?AccessibilityManager -- sendAccessibilityEvent(event); 獲取遠(yuǎn)程的AMS 通過(guò)getServiceLocked()獲取本地Binder,然后通過(guò)service.sendAccessibilityEvent(dispatchedEvent, userId)去調(diào)用AMS的sendAccessibilityEvent方法挟阻。

然后是分發(fā)琼娘,接著剛才的AccessibilityManagerService.java-- sendAccessibilityEvent()說(shuō)

●?AccessibilityManagerService.java --sendAccessibilityEvent()

●?AccessibilityManagerService.java --notifyAccessibilityServicesDelayedLocked(),AMS會(huì)維護(hù)一個(gè)綁定AS的List(mBoundServices)附鸽,List中每一個(gè)AccessibilityServiceConnection對(duì)應(yīng)一個(gè)綁定的AS脱拼,因此遍歷mBoundServices,獲取其中的serviceconection 然后去到AccessibilityServiceConnection的notifyAccessibilityEvent()函數(shù)坷备。

●?AbstractAccessibilityServiceConnection.java-- notifyAccessibilityEvent()

●?AbstractAccessibilityServiceConnection.java-- notifyAccessibilityEventInternal()? ?在notifyAccessibilityEventInternal()中熄浓,listener是AS的本地Binder(IAccessibilityServiceClient類型),最終是回調(diào)到了AS的onAccessibilityEvent()省撑。到這里Dispatch的部分就結(jié)束了赌蔑。

剩下回調(diào),回調(diào)沒(méi)什么好說(shuō)的竟秫,就是調(diào)用方法娃惯。

而onAccessibilityEvent()方法是繼承了AccessibilityService必須重寫的。

原理和源碼解析的結(jié)論

1.輔助功能通過(guò)在后臺(tái)中運(yùn)行無(wú)障礙服務(wù)肥败,通過(guò)AccessibilityEvent接收指定事件的回調(diào)

2.Accessibility服務(wù)框架類似于hook在Android View組件樹中的一套實(shí)現(xiàn)趾浅,它并不是獨(dú)立的一套機(jī)制,而是”寄生”在View的顯示馒稍、事件分發(fā)的流程中皿哨。

●?功能實(shí)現(xiàn)依賴于ViewRootImpl, ViewGroup, View視圖層級(jí)管理的基本架構(gòu)。在視圖變化時(shí)發(fā)出事件纽谒、當(dāng)收到視圖操作請(qǐng)求時(shí)也能夠作出響應(yīng)证膨。

●?system_server在實(shí)現(xiàn)該功能的過(guò)程中扮演著中間人的角色。當(dāng)被監(jiān)聽APP視圖變化時(shí)鼓黔,APP首先會(huì)發(fā)出事件到system_server央勒,隨后再中轉(zhuǎn)到監(jiān)聽者APP端。當(dāng)監(jiān)聽者APP想要執(zhí)行視圖操作時(shí)请祖,也是首先在system_server中找到對(duì)應(yīng)的客戶端binder proxy订歪,再調(diào)用相應(yīng)接口調(diào)用到被監(jiān)聽APP中。完成相關(guān)操作后肆捕,通過(guò)已經(jīng)獲取到的監(jiān)聽APP binder proxy句柄刷晋,直接binder call到對(duì)應(yīng)的監(jiān)聽客戶端。

3.無(wú)障礙權(quán)限十分重要,切記不可濫用眼虱,APP自身也需要有足夠的安全意識(shí)喻奥,防止惡意應(yīng)用通過(guò)該服務(wù)獲取用戶隱私信息

怎么用(如何開發(fā)無(wú)障礙服務(wù))

剛剛說(shuō)到,為什么輔助功能可以監(jiān)聽用戶的操作捏悬,界面變化撞蚕,并根據(jù)需要進(jìn)行反饋,那怎么使用呢过牙,我們繼續(xù)探究

一甥厦、創(chuàng)建服務(wù)類

繼承AccessibilityService 類,重寫onServiceConnected()方法寇钉、onAccessibilityEvent()方法和onInterrupt()方法

●?onServiceConnected (可選)系統(tǒng)成功綁定該服務(wù)時(shí)被觸發(fā)刀疙,也就是當(dāng)你在設(shè)置中開啟相應(yīng)的服務(wù),系統(tǒng)成功的綁定了該服務(wù)時(shí)會(huì)觸發(fā)扫倡,通常我們可以在這里做一些初始化操作

●?onUnbind(Intent intent) (可選)系統(tǒng)要關(guān)閉該服務(wù)是谦秧,將調(diào)用此方法。主要用來(lái)釋放資源撵溃。

●?onAccessibilityEvent(AccessibilityEvent event) 有關(guān)AccessibilityEvent事件的回調(diào)函數(shù)疚鲤,系統(tǒng)通過(guò)sendAccessibiliyEvent()不斷的發(fā)送AccessibilityEvent到此處

● onInterrupt 系統(tǒng)需要中斷AccessibilityService反饋時(shí),將調(diào)用此方法缘挑。AccessibilityService反饋包括服務(wù)發(fā)起的震動(dòng)集歇、音頻等行為。

二卖哎、聲明服務(wù)

像其他Service服務(wù)一樣,需要在AndroidManifest.xml中聲明該服務(wù).除此之外,該服務(wù)還必須配置以下幾項(xiàng)鬼悠,否則都會(huì)使該服務(wù)沒(méi)有反應(yīng):

?●配置<intent-filter>,固定的action:android.accessibilityservice.AccessibilityService

?●聲明BIND_ACCESSIBILITY_SERVICE權(quán)限,以便系統(tǒng)能夠綁定該服務(wù)(4.0版本后要求)

?●android:label:在無(wú)障礙列表中顯示該服務(wù)的名字

三、配置服務(wù)參數(shù)

配置用來(lái)接受指定類型的事件亏娜,監(jiān)聽指定package,檢索窗口內(nèi)容蹬挺,獲取事件類型的時(shí)間等等维贺。其配置服務(wù)參數(shù)有兩種方法:

?● 方法一:安卓4.0之后可以通過(guò)meta-data標(biāo)簽指定xml文件進(jìn)行配置

accessibilityEventTypes:表示該服務(wù)對(duì)界面中的哪些變化感興趣,即哪些事件通知巴帮,比如窗口打開溯泣,滑動(dòng),焦點(diǎn)變化榕茧,長(zhǎng)按等垃沦。具體的值可以在AccessibilityEvent類中查到,如typeAllMask表示接受所有的事件通知

accessibilityFeedbackType:表示反饋方式用押,比如是語(yǔ)音播放肢簿,還是震動(dòng)

canRetrieveWindowContent:表示該服務(wù)能否訪問(wèn)活動(dòng)窗口中的內(nèi)容。也就是如果你希望在服務(wù)中獲取窗體內(nèi)容,則需要設(shè)置其值為true

description:對(duì)該無(wú)障礙功能的描述

notificationTimeout:接受事件的時(shí)間間隔池充,通常將其設(shè)置為100即可

packageNames:表示對(duì)該服務(wù)是用來(lái)監(jiān)聽哪個(gè)包的產(chǎn)生的事件

?● ?方法二:通過(guò)代碼動(dòng)態(tài)配置參數(shù)(setServiceInfo(AccessibilityServiceInfo))

AccessibilityServiceInfo類被用于配置AccessibilityService信息桩引,該類中包含了大量用于配置的常量字段及用來(lái)xml屬性,常見的有:accessibilityEventTypes收夸,canRequestFilterKeyEvents坑匠,packageNames等等

https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityServiceInfo

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

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

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

四、啟動(dòng)服務(wù)

在設(shè)置->輔助功能中便可以找到我們的服務(wù).該服務(wù)默認(rèn)處在關(guān)閉狀態(tài),需要手動(dòng)開啟.

也可以在app中跳轉(zhuǎn)到設(shè)置頁(yè)卧惜。

五厘灼、處理事件信息

onAccessibilityEvent(AccessibilityEvent event)是該服務(wù)的核心方法,其中參數(shù)event封裝來(lái)自界面相關(guān)事件的信息,比如我們可以獲得該事件的事件類型,進(jìn)而根據(jù)起類型選擇不同的處理方式:

常見種類如圖

六、獲取節(jié)點(diǎn)信息

獲取了界面窗口變化后咽瓷,這個(gè)時(shí)候就要獲取控件的節(jié)點(diǎn)手幢。整個(gè)窗口的節(jié)點(diǎn)本質(zhì)是個(gè)樹結(jié)構(gòu),通過(guò)以下操作節(jié)點(diǎn)信息

獲取窗口節(jié)點(diǎn)(根節(jié)點(diǎn))

AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();

獲取指定子節(jié)點(diǎn)(控件節(jié)點(diǎn))

//通過(guò)文本找到對(duì)應(yīng)的節(jié)點(diǎn)集合

List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(text);

//通過(guò)控件ID找到對(duì)應(yīng)的節(jié)點(diǎn)集合忱详,如com.tencent.mm:id/gd

List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(clickId);

AccessibilityService 獲取View的Id

獲取id的一些方法

●?layoutInspector

●?Uiautomator viewer

隨緣围来,各種原因,成功率很低匈睁。截圖失敗或者超時(shí)

●?hierarchy view

相對(duì)可靠监透。

可以在命令行工具中,執(zhí)行如下命令 得到相關(guān)文件

adb shell uiautomator dump

執(zhí)行成功 系統(tǒng)會(huì)返回 UI hierchary dumped to: /mnt/sdcard/window_dump.xml

當(dāng)然 這個(gè)文件地址也是可以更改的航唆。 adb shell uiautomator dump [file]

七胀蛮、模擬節(jié)點(diǎn)點(diǎn)擊

當(dāng)我們獲取了節(jié)點(diǎn)信息之后,對(duì)控件節(jié)點(diǎn)進(jìn)行模擬點(diǎn)擊糯钙、長(zhǎng)按等操作粪狼,AccessibilityNodeInfo類提供了performAction()方法讓我們執(zhí)行模擬操作,具體操作可看官方文檔介紹任岸,這里列舉常用的操作

//模擬點(diǎn)擊

accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);

//模擬長(zhǎng)按

accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);

//模擬獲取焦點(diǎn)

accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);

//模擬粘貼

accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);

八再榄、示例及代碼——自動(dòng)安裝app

接下來(lái)用例子說(shuō)明下怎么使用無(wú)障礙服務(wù)

平時(shí)我們點(diǎn)擊安裝包進(jìn)行安裝的時(shí)候,會(huì)彈出界面讓我們確認(rèn)享潜。一般來(lái)說(shuō)我們就是點(diǎn)擊下一步困鸥,安裝,然后安裝完成后點(diǎn)擊打開或者完成剑按。

如果用無(wú)障礙服務(wù)的話疾就,是可以在點(diǎn)擊安裝包的時(shí)候直接自動(dòng)幫忙點(diǎn)了下一步,安裝之類的艺蝴。

具體做法就是在 onAccessibilityEvent()中猬腰,判斷是否安裝程序進(jìn)程,然后進(jìn)行下相應(yīng)的點(diǎn)擊動(dòng)作猜敢,代碼如右圖所示 這邊用的手機(jī)是小米姑荷,所以是小米的packgeInstaller的判斷盒延。如果是的話,就開始執(zhí)行找控件點(diǎn)擊的邏輯

小作業(yè)試驗(yàn):完成自動(dòng)回復(fù)的功能

首先我們知道一般軟件厢拭,如微信接收信息時(shí)是有通知的述雾,顯示在通知欄中苗分,所以我們的事件監(jiān)聽需要監(jiān)聽通知欄變化

通知的點(diǎn)擊打開是可以進(jìn)入到相應(yīng)的聊天頁(yè)面的渔工。

如果想在聊天頁(yè)面實(shí)現(xiàn)回復(fù)八堡,就是在輸入框中輸入文字,然后點(diǎn)擊發(fā)送就可以楞捂,剩下的回調(diào)由微信的程序完成

可以簡(jiǎn)單實(shí)現(xiàn)下薄坏,如果真的想通過(guò)無(wú)障礙服務(wù)實(shí)現(xiàn)自動(dòng)回復(fù),邏輯會(huì)嚴(yán)謹(jǐn)很多寨闹,首先判斷依據(jù)需要跳轉(zhuǎn)聊天頁(yè)的依據(jù)就不會(huì)這么簡(jiǎn)單胶坠。然后是場(chǎng)景也有多種區(qū)分,如后臺(tái)繁堡,息屏沈善,跳轉(zhuǎn)失敗,代理清除通知等

回復(fù)的邏輯也會(huì)復(fù)雜很多椭蹄,接入半自動(dòng)回復(fù)機(jī)器人接口不用說(shuō)闻牡,還有查找輸入框控件失敗,群聊绳矩,多條信息罩润,是否需要執(zhí)行自動(dòng)回復(fù)的邏輯判斷等

怎么防(防止無(wú)障礙服務(wù)外掛的一些做法)

通過(guò)原理和源碼查看,我們知道了無(wú)障礙服務(wù)是內(nèi)嵌到整個(gè)android的view層類里的翼馆,但是還是有缺陷的

如通過(guò)Onclick實(shí)現(xiàn)的點(diǎn)擊事件割以,可以捕捉到,但通過(guò)onTouchEvent實(shí)現(xiàn)的的點(diǎn)擊事件应媚,捕捉不到

如有獲取節(jié)點(diǎn)文字的方法严沥,但沒(méi)有提供獲取圖片數(shù)據(jù)的方法,導(dǎo)致外掛搶票實(shí)現(xiàn)驗(yàn)證碼輸入不太可能珍特。

那么我們可以怎么防御呢祝峻,有以下一些做法

AccessibilityManager有提供獲取安裝了的無(wú)障礙服務(wù)和開啟的無(wú)障礙的服務(wù)的方法。從而讓我們可以知道用戶有哪些無(wú)障礙服務(wù)扎筒,及運(yùn)行的服務(wù)有哪些。幫助我們確定自動(dòng)點(diǎn)擊的外掛來(lái)源酬姆,從而在打開外掛后有一個(gè)警告

了解AccessibilityServices源碼之后嗜桌,我們知道其內(nèi)部核心原理就是調(diào)用TextView的findViewsWithText方法。只要復(fù)寫這個(gè)方法辞色,就可以屏蔽文案檢查

AccessibilityServices執(zhí)行點(diǎn)擊事件最終在調(diào)用View的mOnClickListener骨宠。可以利用onTouch代替onClick屏蔽服務(wù)調(diào)用點(diǎn)擊的動(dòng)作

某些微信紅包插件會(huì)監(jiān)控Notification的彈出,那么我們是否可以隨意發(fā)送這樣的Event出來(lái)层亿,從而混干擾外掛插件的運(yùn)行邏輯桦卒。這種做法大部分情況比較雞肋,也看外掛同學(xué)的邏輯嚴(yán)不嚴(yán)謹(jǐn)

這個(gè)其實(shí)是繼第一種方式后的操作匿又,在收集好已知外掛的信息后方灾,設(shè)立黑名單,遍歷系統(tǒng)內(nèi)部所有已安裝的app碌更,鑒別package name 和app name裕偿。執(zhí)行相應(yīng)處理

參考資料

?官方介紹

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

?android 輔助功能google官方示例

https://github.com/googlesamples/android-BasicAccessibility

?WechatHelper 微信助手

https://github.com/coder-pig/WechatHelper

?AccessibilityService分析與防御

https://lizhaoxuan.github.io/2018/01/27/AccessibilityService%E5%88%86%E6%9E%90%E4%B8%8E%E9%98%B2%E5%BE%A1/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痛单,隨后出現(xiàn)的幾起案子嘿棘,更是在濱河造成了極大的恐慌,老刑警劉巖旭绒,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸟妙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挥吵,警方通過(guò)查閱死者的電腦和手機(jī)重父,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蔫劣,“玉大人坪郭,你說(shuō)我怎么就攤上這事÷龃保” “怎么了歪沃?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嫌松。 經(jīng)常有香客問(wèn)我沪曙,道長(zhǎng),這世上最難降的妖魔是什么萎羔? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任液走,我火速辦了婚禮,結(jié)果婚禮上贾陷,老公的妹妹穿的比我還像新娘缘眶。我一直安慰自己,他們只是感情好髓废,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布巷懈。 她就那樣靜靜地躺著,像睡著了一般慌洪。 火紅的嫁衣襯著肌膚如雪顶燕。 梳的紋絲不亂的頭發(fā)上凑保,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音涌攻,去河邊找鬼欧引。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恳谎,可吹牛的內(nèi)容都是我干的芝此。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惠爽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼癌蓖!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起婚肆,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤租副,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后较性,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體用僧,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年赞咙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了责循。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡攀操,死狀恐怖院仿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情速和,我是刑警寧澤歹垫,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站颠放,受9級(jí)特大地震影響排惨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碰凶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一暮芭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧欲低,春花似錦辕宏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至恤磷,卻和暖如春面哼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扫步。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工魔策, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人河胎。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓闯袒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親游岳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子政敢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355