前言
在手機(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/