Viele Android-Benutzer erleben verschiedene Situationen, die dazu führen, dass sie auf unterschiedliche Weise mit ihren Telefonen interagieren. Für Benutzer, die aus Seh-, Hör- oder anderen physischen Gründen nicht in der Lage sind, Android-Smartphones zu verwenden, bietet Android Eingabehilfen und -dienste, die diesen Benutzern helfen, das Gerät einfacher zu bedienen, einschließlich Text-to-Speech, taktiles Feedback, Gestenbedienung und Trackball und Handle-Bedienung. Entwickler können ihre eigenen Barrierefreiheitsdienste erstellen, die die Benutzerfreundlichkeit von Anwendungen verbessern können, z. B. akustische Eingabeaufforderungen, physisches Feedback und andere optionale Betriebsmodi.
Seine spezifische Implementierung besteht darin, im Hintergrund über den AccessibilityService-Dienst zu laufen und über AccessibilityEvent Rückrufe für bestimmte Ereignisse zu empfangen. Solche Ereignisse stellen einige Zustandsübergänge des Benutzers in der Benutzeroberfläche dar, z. B.: Fokus geändert, eine Schaltfläche wurde angeklickt usw. Solche Dienste können optional die Möglichkeit haben, den Inhalt des aktiven Fensters anzufordern. Einfach ausgedrückt ist AccessibilityService ein Hintergrundüberwachungsdienst. Wenn sich der von Ihnen überwachte Inhalt ändert, wird die Rückrufmethode des Hintergrunddienstes aufgerufen.
Schreiben Sie Ihre eigene Service-Klasse und überschreiben Sie die Methoden onServiceConnected(), onAccessibilityEvent() und onInterrupt()
public class QHBAccessibilityService extends AccessibilityService {
/**
* 当启动服务的时候就会被调用
*/
@ Override
protected void onServiceConnected () {
super . onServiceConnected ();
}
/**
* 监听窗口变化的回调
*/
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
}
/**
* 中断服务的回调
*/
@ Override
public void onInterrupt () {
}
}
Im Folgenden finden Sie eine Einführung in die häufig verwendeten Methoden in AccessibilityService
Da es sich um einen Hintergrunddienst handelt, müssen wir die Dienstinformationen in Manifesten konfigurieren
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
</ service >
Wir müssen darauf achten: Jeder Informationskonfigurationsfehler führt dazu, dass der Dienst nicht mehr reagiert
Das Konfigurieren von Dienstparametern bezieht sich auf: Konfigurieren zum Akzeptieren von Ereignissen bestimmter Typen, zum Abhören bestimmter Pakete, zum Abrufen von Fensterinhalten, zum Abrufen der Zeit von Ereignistypen usw. Es gibt zwei Möglichkeiten, Dienstparameter zu konfigurieren:
Fügen Sie das Metadaten-Tag zu den ursprünglichen Manifesten hinzu, um die XML-Datei anzugeben
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
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 >
Als nächstes erfolgt die Konfiguration der Datei accessibility_service_config
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< accessibility-service xmlns : android = " http://schemas.android.com/apk/res/android "
android : accessibilityEventTypes = " typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged "
android : accessibilityFeedbackType = " feedbackGeneric "
android : accessibilityFlags = " flagDefault "
android : canRetrieveWindowContent = " true "
android : description = " @string/description "
android : notificationTimeout = " 100 "
android : packageNames = " com.tencent.mm " />
Im Folgenden finden Sie eine Einführung in XML-Parameter
accessibilityEventTypes: Gibt an, an welchen Änderungen in der Schnittstelle der Dienst interessiert ist, d. h. welche Ereignisse benachrichtigt werden, z. B. Fensteröffnen, Schieben, Fokuswechsel, langes Drücken usw. Der spezifische Wert kann in der AccessibilityEvent-Klasse gefunden werden. TypAllMask bedeutet beispielsweise das Akzeptieren aller Ereignisbenachrichtigungen.
accessibilityFeedbackType: gibt die Feedback-Methode an, z. B. Sprachwiedergabe oder Vibration
canRetrieveWindowContent: Gibt an, ob der Dienst auf den Inhalt im aktiven Fenster zugreifen kann. Das heißt, wenn Sie den Formularinhalt im Dienst abrufen möchten, müssen Sie seinen Wert auf true setzen
Beschreibung: Eine Beschreibung der Barrierefreiheitsfunktion, wie in der Abbildung unten dargestellt
notificationTimeout: Das Zeitintervall für die Annahme von Ereignissen, normalerweise auf 100 eingestellt
packageNames: Gibt an, welches Paket der Dienst zur Überwachung von Ereignissen verwendet. Hier nehmen wir den Paketnamen von WeChat als Beispiel.
Konfigurieren Sie AccessibilityServiceInfo-Informationen für unseren AccessibilityService über Code. Hier können wir sie in eine Methode zur Einstellung extrahieren
private void settingAccessibilityInfo () {
String [] packageNames = { "com.tencent.mm" };
AccessibilityServiceInfo mAccessibilityServiceInfo = new AccessibilityServiceInfo ();
// 响应事件的类型,这里是全部的响应事件(长按,单击,滑动等)
mAccessibilityServiceInfo . eventTypes = AccessibilityEvent . TYPES_ALL_MASK ;
// 反馈给用户的类型,这里是语音提示
mAccessibilityServiceInfo . feedbackType = AccessibilityServiceInfo . FEEDBACK_SPOKEN ;
// 过滤的包名
mAccessibilityServiceInfo . packageNames = packageNames ;
setServiceInfo ( mAccessibilityServiceInfo );
}
Die AccessibilityServiceInfo-Klasse wird zum Konfigurieren von AccessibilityService-Informationen verwendet. Diese Klasse enthält eine große Anzahl konstanter Felder für Konfigurations- und XML-Attribute, darunter: accessibilityEventTypes, canRequestFilterKeyEvents usw.
Hier müssen wir diese Funktion in der Barrierefreiheitsfunktion manuell aktivieren, sonst können wir nicht fortfahren. Sie können die Barrierefreiheitsfunktionsliste des Systems über den folgenden Code öffnen
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
Da wir die Benachrichtigungsleiste und Schnittstelle des Ereignisses überwachen, wird unser Ereignis über onAccessibilityEvent zurückgerufen, wenn sich die Benachrichtigungsleiste oder Schnittstelle der angegebenen Paketnamen ändert, und dann wird das Ereignis verarbeitet.
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
switch ( eventType ) {
//当通知栏发生改变时
case AccessibilityEvent . TYPE_NOTIFICATION_STATE_CHANGED :
break ;
//当窗口的状态发生改变时
case AccessibilityEvent . TYPE_WINDOW_STATE_CHANGED :
break ;
}
}
Wenn wir eine Benachrichtigung auf WeChat erhalten, wird eine Push-Nachricht in der Statusleiste angezeigt. Zu diesem Zeitpunkt wird sie von TYPE_NOTIFICATION_STATE_CHANGED überwacht und der darin enthaltene Inhalt wird ausgeführt. Diesmal wird dies der Fall sein wird von TYPE_WINDOW_STATE_CHANGED überwacht. Führen Sie den darin enthaltenen Inhalt aus
AccessibilityEvent-Methoden
Nachdem Sie die Änderungen am Schnittstellenfenster erhalten haben, müssen Sie zu diesem Zeitpunkt die Steuerknoten abrufen. Die Knoten des gesamten Fensters sind im Wesentlichen eine Baumstruktur. Die Knoteninformationen werden wie folgt verwaltet
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
Nachdem wir die Knoteninformationen erhalten haben, können wir simulierte Klicks, langes Drücken und andere Vorgänge an den Steuerknoten ausführen. Die AccessibilityNodeInfo-Klasse stellt die Methode performAction() bereit, um simulierte Vorgänge durchzuführen. Weitere Informationen finden Sie in der offiziellen Dokumentation . Häufig verwendete Operationen sind hier aufgelistet.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
Wenn unser Telefon mit dem USB-Kabel verbunden ist, wählen Sie das Gerät im Android Device Monitor aus und öffnen Sie das Tool „Dump View Hierarchy for UI Automator“, über das wir Steuerinformationen erhalten können
F:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
meldet immer einen Nullzeiger. A: Ich bin auch auf ein Problem wie Ihres gestoßen. Ich habe gerade mit der Konfiguration im Code begonnen und habe auch das Gefühl, dass ich dies nicht geschrieben habe ", aber das war nicht der Fall. Ich habe die Einstellung gefunden, die android:canRetrieveWindowContent="true" entspricht, also habe ich sie geändert, um sie in XML zu konfigurieren, und es war in Ordnung.
F: Wie erhalten Sie diese Klassennamen com.tencent.mm.ui.LauncherUI? A: String className = event.getClassName().toString(); Verwenden Sie das Protokoll, um es auszudrucken, und öffnen Sie WeChat, um die Protokollinformationen anzuzeigen
Originaltext: Hensen_s Blog