De nombreux utilisateurs d'Android se trouvent dans diverses situations qui les amènent à interagir avec leur téléphone de différentes manières. Pour les utilisateurs qui ne peuvent pas utiliser les smartphones Android pour des raisons visuelles, auditives ou pour d'autres raisons physiques, Android fournit des fonctions et des services d'accessibilité pour aider ces utilisateurs à utiliser l'appareil plus simplement, notamment la synthèse vocale, le retour tactile, les opérations gestuelles, le trackball. et opération de poignée. Les développeurs peuvent créer leurs propres services d'accessibilité, qui peuvent améliorer la convivialité des applications, telles que des invites sonores, des retours physiques et d'autres modes de fonctionnement facultatifs.
Son implémentation spécifique consiste à s'exécuter en arrière-plan via le service AccessibilityService et à recevoir des rappels pour les événements spécifiés via AccessibilityEvent. De tels événements représentent certaines transitions d'état de l'utilisateur dans l'interface, telles que : le focus a changé, un bouton a été cliqué, etc. Ces services peuvent éventuellement avoir la capacité de demander le contenu de la fenêtre active. En termes simples, AccessibilityService est un service de surveillance en arrière-plan Lorsque le contenu que vous surveillez change, la méthode de rappel du service en arrière-plan sera appelée.
Écrivez votre propre classe Service et remplacez la méthode onServiceConnected(), la méthode onAccessibilityEvent() et la méthode 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 () {
}
}
Ce qui suit est une introduction aux méthodes couramment utilisées dans AccessibilityService
Puisqu'il s'agit d'un service en arrière-plan, nous devons configurer les informations du service dans les manifestes
< 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 >
Il faut faire attention : toute erreur de configuration des informations rendra le service insensible
La configuration des paramètres de service fait référence à : la configuration pour accepter des événements de types spécifiés, écouter les packages spécifiés, récupérer le contenu de la fenêtre, obtenir l'heure des types d'événements, etc. Il existe deux manières de configurer les paramètres du service :
Ajoutez la balise de métadonnées aux manifestes d'origine pour spécifier le fichier XML
< 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 >
Vient ensuite la configuration du fichieraccessibility_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 " />
Ce qui suit est une introduction aux paramètres XML
accessibilityEventTypes : indique les changements dans l'interface qui intéressent le service, c'est-à-dire quels événements sont notifiés, tels que l'ouverture de fenêtre, le glissement, le changement de focus, l'appui long, etc. La valeur spécifique peut être trouvée dans la classe AccessibilityEvent. Par exemple, typeAllMask signifie accepter toutes les notifications d'événements.
accessibilityFeedbackType : indique la méthode de retour, telle que la lecture vocale ou les vibrations.
canRetrieveWindowContent : indique si le service peut accéder au contenu de la fenêtre active. Autrement dit, si vous souhaitez obtenir le contenu du formulaire dans le service, vous devez définir sa valeur sur true.
description : une description de la fonctionnalité d'accessibilité, comme indiqué dans la figure ci-dessous
notificationTimeout : l'intervalle de temps pour accepter les événements, généralement défini sur 100
packageNames : indique le package que le service est utilisé pour surveiller les événements. Ici, nous prenons le nom du package de WeChat comme exemple.
Configurez les informations AccessibilityServiceInfo pour notre AccessibilityService via le code. Ici, nous pouvons les extraire dans une méthode de configuration.
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 );
}
La classe AccessibilityServiceInfo est impliquée ici. La classe AccessibilityServiceInfo est utilisée pour configurer les informations AccessibilityService. Cette classe contient un grand nombre de champs constants pour la configuration et les attributs XML courants incluent : AccessibilityEventTypes, canRequestFilterKeyEvents, packageNames, etc.
Ici, nous devons activer manuellement cette fonction dans la fonction d'accessibilité, sinon nous ne pouvons pas continuer. Vous pouvez ouvrir la liste des fonctions d'accessibilité du système via le code suivant.
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
Puisque nous surveillons la barre de notification et l'interface de l'événement, lorsque la barre de notification ou l'interface des packagesNames spécifiés change, notre événement sera rappelé via onAccessibilityEvent, puis l'événement sera traité.
@ 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 ;
}
}
Lorsque nous recevons une notification sur WeChat, un message push arrivera dans la barre d'état. À ce moment, il sera surveillé par TYPE_NOTIFICATION_STATE_CHANGED et le contenu à l'intérieur sera exécuté lorsque nous changerons d'interface WeChat ou utiliserons WeChat, cette fois. être surveillé par TYPE_WINDOW_STATE_CHANGED Exécuter le contenu à l'intérieur.
Méthodes AccessibilityEvent
Après avoir obtenu les modifications de la fenêtre d'interface, il est nécessaire d'obtenir les nœuds de contrôle à ce moment-là. Les nœuds de la fenêtre entière sont essentiellement une structure arborescente. Les informations sur les nœuds sont exploitées comme suit.
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
Après avoir obtenu les informations sur le nœud, nous pouvons effectuer des clics simulés, des appuis longs et d'autres opérations sur les nœuds de contrôle. La classe AccessibilityNodeInfo fournit la méthode performAction() pour nous permettre d'effectuer des opérations simulées. Pour des opérations spécifiques, veuillez vous référer à la documentation officielle. . Les opérations couramment utilisées sont répertoriées ici.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
Lorsque notre téléphone est connecté au câble USB, sélectionnez l'appareil dans Android Device Monitor et ouvrez l'outil Dump View Hierarchy for UI Automator, grâce auquel nous pouvons obtenir des informations de contrôle
Q :
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
signale toujours un pointeur nul. Le blogueur a-t-il rencontré ce problème ? J'ai également rencontré un problème comme le vôtre. Je pense que c'est dans les "Paramètres du service de configuration". Je viens de commencer à le configurer dans le code, et il a également renvoyé null. J'ai l'impression que je n'ai pas écrit ceci android:canRetrieveWindowContent="true. ", mais ce n'est pas le cas. J'ai trouvé le paramètre correspondant à android:canRetrieveWindowContent="true", je l'ai donc modifié pour le configurer en XML, et tout allait bien.
Q : Comment obtenez-vous ces noms de classe com.tencent.mm.ui.LauncherUI ? A : String className = event.getClassName().toString(); Utilisez le journal pour l'imprimer et ouvrez WeChat pour afficher les informations du journal.
Texte original : le blog de Hensen_