天天看點

無障礙服務AccessibilityService詳解

無障礙服務

什麼是無障礙?為什麼需要無障礙?

讓應用使用起來沒有障礙。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(有兩個服務時用"|"隔開)

無障礙服務的流程分析

總體流程如下:

無障礙服務AccessibilityService詳解

AccessibilityEvent事件是如何産生和發送的?

無障礙服務AccessibilityService詳解
  1. view擷取焦點或者被選中時,内部會調用相關的方法初始化AccessibilityEvent的相關資訊;
  2. 在onPopulateAccessibilityEventInternal()方法中設定AccessibilityEvent文本,在onInitializeAccessibilityNodeInfoInternal()方法中設定AccessibilityNodeInfo的文本;
  3. 調用ViewParent的實作類ViewRootImpl中requestSendAccessibilityEvent()方法;
  4. AccessibilityManager通過IAccessibilityManager跨程序調用AccessibilityManagerService的sendAccessibilityEvent()方法;
  5. 最終通過周遊AccessibilityServiceConnection将事件消息分發到各個AccessibilityService服務中。

AccessibilityService是如何接收AccessibilityEvent事件?

無障礙服務AccessibilityService詳解
  1. AccessibilityService是一個抽象類,繼承于Service,提供兩個抽象方法onAccessibilityEvent() 和 onInterrupt();實作了 onBind() 方法,在其中建立了一個IAccessibilityServiceClientWrapper對象。
  2. 而IAccessibilityServiceClientWrapper繼承于IAccessibilityServiceClient.Stub類,可以猜測到,AccessibilityService為一個遠端Service,是用跨程序進行通信的。
  3. 當Client端調用onAccessibilityEvent()方法時,通過HandlerCaller處理消息,并調用CallBacks的onAccessibilityEvent()方法,最後在回調中調用 AccessibilityService.this.onAccessibilityEvent(event)。

AccessibilityService是如何與用戶端綁定的?

無障礙服務AccessibilityService詳解
  1. AccessibilityManagerService初始化時,注冊應用螢幕和使用者狀态改變的廣播監聽,AccessibilityManagerService是一個系統服務,由SystemService啟動;
  2. 應用螢幕廣播是用來監聽應用狀态的改變;
  3. 以及監聽使用者切換、使用者解鎖、使用者被移除等狀态改變;
  4. 當狀态改變時,調用updateServicesLocked()周遊無障礙服務清單,判斷是否啟用,進行綁定或解綁;
  5. AccessibilityServiceConnection.java>>>bindLocked()>>>>mContext.bindServiceAsUser();

如何通過AccessibilityService遠端操作view?

圖檔來自于:https://blog.csdn.net/u010255127/article/details/79184399

無障礙服務AccessibilityService詳解

無障礙服務的應用

  1. TalkBack;
  2. 自動擷取短信驗證碼;
  3. 自動化測試;
  4. 外挂:搶紅包、搶單;

無障礙服務防禦

  1. 檢測 or 禁止相關外挂的輔助模式開啟。

    a)通過getInstalledAccessibilityServiceList()方法擷取所有的無障礙服務,檢視這些服務是否有在監控你的應用;

    b)通過ContentObserver監聽enabled_accessibility_services屬性值變化,當有服務開啟重複a)步驟檢測,防止被惡意軟體監控;

  2. Event幹擾:通過發送無規律的AccessibilityEvent來幹擾惡意軟體的邏輯判斷。
  3. onTouch替換onClick,屏蔽點選事件。
  4. 重寫View的findViewsWithText()方法,防止插件通過文本查找到相關的view。

繼續閱讀