無障礙服務
什麼是無障礙?為什麼需要無障礙?
讓應用使用起來沒有障礙。Android應用的目标是讓所有人都可以使用,包括但不限于視力受損、色盲、聽力受損、精細動作失能的人。要想這些有無障礙需求的使用者有更好的體驗,那麼開發應用就要多考慮無障礙功能。
Android無障礙服務
無障礙服務是 Android架構的一項功能,旨在為了給使用Android裝置的殘障人士提供互動回報,讓他們能夠更友善的使用Android裝置。
常見無障礙服務示例
- 開關通路:允許行動不便的 Android 使用者使用一個或多個開關與裝置進行互動。
- 語音通路:允許行動不便的 Android 使用者使用語音指令控制裝置。
- Talkback:視力受損或盲人使用者常用的螢幕閱讀器。
如何建構自己的無障礙服務?
1.建立TestAccessibilityService.java類繼承AccessibilityService;
import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;
/**
* @author fenghaitao
* @time 2021/8/30 12:08
*/
public class TestAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
2.在/res/xml/目錄下建立服務配置檔案accessibility_service_config.xml,在裡面添加相關的配置資訊。
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:packageNames="com.example.android.apis"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagDefault"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>
字段說明:
- description 說明
- packageNames 要監控的應用包名,多個應用用“,”隔開;
- accessibilityEventTypes 此服務希望接收的事件類型;
- accessibilityFlags 輔助功能附加的标志,多個使用 ’ | '分隔,如flagRequestFilterKeyEvents 能夠監聽到系統的實體按鍵;
- accessibilityFeedbackType 回報類型,有語音、視覺、觸覺等;
- notificationTimeout 同一類型的兩個輔助功能事件發送到服務的最短間隔(毫秒,兩個輔助功能事件之間的最小周期);
- canRetrieveWindowContent 輔助功能服務是否能夠取回活動視窗内容的屬性;
- settingsActivity 允許使用者修改輔助功能的activity元件名稱;
也可以運作時在服務的onServiceConnected()方法中動态配置,示例如下:
AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; //事件類型
serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;//設定回饋給使用者的方式
serviceInfo.packageNames = pachage;
serviceInfo.notificationTimeout = 100; //
setServiceInfo(serviceInfo);
3.在AndroidManifest.xml中進行聲明,并引用accessibility_service_config.xml配置檔案。
<service
android:name=".TestAccessibilityService1" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
4.将程式安裝并打開開關。
打開開關方式有兩種:
- 如果系統中有原生的setting應用,可以直接在無障礙條目中打開。
- 通過adb指令設定相關屬性值打開:
settings put secure accessibility_enabled 1
settings put secure enabled_accessibility_services com.cvte.tv.texttospeech/com.cvte.tv.texttospeech.TTSAccessibilityService(有兩個服務時用"|"隔開)
無障礙服務的流程分析
總體流程如下:
AccessibilityEvent事件是如何産生和發送的?
- view擷取焦點或者被選中時,内部會調用相關的方法初始化AccessibilityEvent的相關資訊;
- 在onPopulateAccessibilityEventInternal()方法中設定AccessibilityEvent文本,在onInitializeAccessibilityNodeInfoInternal()方法中設定AccessibilityNodeInfo的文本;
- 調用ViewParent的實作類ViewRootImpl中requestSendAccessibilityEvent()方法;
- AccessibilityManager通過IAccessibilityManager跨程序調用AccessibilityManagerService的sendAccessibilityEvent()方法;
- 最終通過周遊AccessibilityServiceConnection将事件消息分發到各個AccessibilityService服務中。
AccessibilityService是如何接收AccessibilityEvent事件?
- AccessibilityService是一個抽象類,繼承于Service,提供兩個抽象方法onAccessibilityEvent() 和 onInterrupt();實作了 onBind() 方法,在其中建立了一個IAccessibilityServiceClientWrapper對象。
- 而IAccessibilityServiceClientWrapper繼承于IAccessibilityServiceClient.Stub類,可以猜測到,AccessibilityService為一個遠端Service,是用跨程序進行通信的。
- 當Client端調用onAccessibilityEvent()方法時,通過HandlerCaller處理消息,并調用CallBacks的onAccessibilityEvent()方法,最後在回調中調用 AccessibilityService.this.onAccessibilityEvent(event)。
AccessibilityService是如何與用戶端綁定的?
- AccessibilityManagerService初始化時,注冊應用螢幕和使用者狀态改變的廣播監聽,AccessibilityManagerService是一個系統服務,由SystemService啟動;
- 應用螢幕廣播是用來監聽應用狀态的改變;
- 以及監聽使用者切換、使用者解鎖、使用者被移除等狀态改變;
- 當狀态改變時,調用updateServicesLocked()周遊無障礙服務清單,判斷是否啟用,進行綁定或解綁;
- AccessibilityServiceConnection.java>>>bindLocked()>>>>mContext.bindServiceAsUser();
如何通過AccessibilityService遠端操作view?
圖檔來自于:https://blog.csdn.net/u010255127/article/details/79184399
無障礙服務的應用
- TalkBack;
- 自動擷取短信驗證碼;
- 自動化測試;
- 外挂:搶紅包、搶單;
無障礙服務防禦
-
檢測 or 禁止相關外挂的輔助模式開啟。
a)通過getInstalledAccessibilityServiceList()方法擷取所有的無障礙服務,檢視這些服務是否有在監控你的應用;
b)通過ContentObserver監聽enabled_accessibility_services屬性值變化,當有服務開啟重複a)步驟檢測,防止被惡意軟體監控;
- Event幹擾:通過發送無規律的AccessibilityEvent來幹擾惡意軟體的邏輯判斷。
- onTouch替換onClick,屏蔽點選事件。
- 重寫View的findViewsWithText()方法,防止插件通過文本查找到相關的view。