The purpose of this article is to introduce the AccessibilityService if more elegant use, and use the process encountered problems, how to solve.
Introduce a,
Helper services run in the background and receive a callback from the system when AccessibilityEvent is triggered. Such events represent some state transition in the user interface; for example, the focus has changed, a button has been clicked, and so on. Now it is often used in automated businesses, such as wechat automatic red envelope snatching plug-in, wechat business automatically add nearby friends, automatically comment on friends, like friends circle, and even used in group control system to brush orders.
Second, the configuration
1. Create Service and inherit AccessibilityService
/** * Core Services: Created by behindeye on 2017/6/13. */ public class TaskService_ extends AccessibilityService{@override public Void onAccessibilityEvent(AccessibilityEvent event) {// Override public void onInterrupt() {}}Copy the code
2. Configure androidmanifest.xml
<service
android:name=".service.TaskService"
android:enabled="true"
android:exported="true"
android:label="@string/app_name_setting"
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>
Copy the code
3. Create an XML folder in the res directory and a configuration file swt.xml
<? The XML version = "1.0" encoding = "utf-8"? > <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" <! - monitoring action -- > android: accessibilityEventTypes = "typeAllMask" <! Provide feedback types, voice vibrations, etc. --> android:accessibilityFeedbackType="feedbackGeneric" <! -- Monitor the state of the view. Note that setting flagDefault will change the state of the view. Does not trigger the AccessibilityEvent(AccessibilityEvent) callback --> android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews|flagReportViewIds|fl agRequestTouchExplorationMode" <! - whether to retrieve the content of the active window, this setting can change at runtime - > android: canRetrieveWindowContent = "true" <! Android :description="@string/description" <! - the same event time interval of - > android: notificationTimeout = "100" <! - monitoring package name - > android: packageNames = "com. Tencent. Mm, com. Eg. Android. AlipayGphone" / >Copy the code
Third, core methods
1. Find the corresponding component according to the interface text (note: the method returns a set, and the found component is not unique, and the text here is not only the text of the TextView we understand, but also the ContentDescription of some components)
accessibilityNodeInfo.findAccessibilityNodeInfosByText(text)
Copy the code
The component id can be obtained by using Android Studio’s built-in tool Monitor. The tool path is: C: \ Users \ Dell \ AppData \ Local \ Android \ Sdk \ tools)
accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id)
Copy the code
Fourth, auxiliary permission to determine whether to enable
public static boolean hasServicePermission(Context ct, Class serviceClass) { int ok = 0; try { ok = Settings.Secure.getInt(ct.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED); } catch (Settings.SettingNotFoundException e) { } TextUtils.SimpleStringSplitter ms = new TextUtils.SimpleStringSplitter(':'); if (ok == 1) { String settingValue = Settings.Secure.getString(ct.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if (settingValue ! = null) { ms.setString(settingValue); while (ms.hasNext()) { String accessibilityService = ms.next(); if (accessibilityService.contains(serviceClass.getSimpleName())) { return true; } } } } return false; }Copy the code
Five, auxiliary opening method
1. In the root authorization environment, you do not need to guide the user to the system Settings page
public static void openServicePermissonRoot(Context ct, Class service) {
String cmd1 = "settings put secure enabled_accessibility_services " + ct.getPackageName() + "/" + service.getName();
String cmd2 = "settings put secure accessibility_enabled 1";
String[] cmds = new String[]{cmd1, cmd2};
ShellUtils.execCmd(cmds, true);
}
Copy the code
2. If the targetSdk version is smaller than 23, some mobile phones can also use the following code to enable permissions, for compatibility, the best try… Catch the following exception
public static void openServicePermission(Context ct, Class serviceClass) { Set<ComponentName> enabledServices = getEnabledServicesFromSettings(ct, serviceClass); if (null == enabledServices) { return; } ComponentName toggledService = ComponentName.unflattenFromString(ct.getPackageName() + "/" + serviceClass.getName()); final boolean accessibilityEnabled = true; enabledServices.add(toggledService); // Update the enabled services setting. StringBuilder enabledServicesBuilder = new StringBuilder(); for (ComponentName enabledService : enabledServices) { enabledServicesBuilder.append(enabledService.flattenToString()); enabledServicesBuilder.append(":"); } final int enabledServicesBuilderLength = enabledServicesBuilder.length(); if (enabledServicesBuilderLength > 0) { enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1); } Settings.Secure.putString(ct.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServicesBuilder.toString()); // Update accessibility enabled. Settings.Secure.putInt(ct.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1:0); } public static Set<ComponentName> getEnabledServicesFromSettings(Context context, Class serviceClass) { String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if (enabledServicesSetting == null) { enabledServicesSetting = ""; } Set<ComponentName> enabledServices = new HashSet<ComponentName>(); TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter(':'); colonSplitter.setString(enabledServicesSetting); while (colonSplitter.hasNext()) { String componentNameString = colonSplitter.next(); ComponentName enabledService = ComponentName.unflattenFromString(componentNameString); if (enabledService ! = null) { if (enabledService.flattenToString().contains(serviceClass.getSimpleName())) { return null; } enabledServices.add(enabledService); } } return enabledServices; }Copy the code
3. Navigate to the system Settings page to enable permissions
public static void jumpSystemSetting(Context ct) {
// jump to setting permission
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ct.startActivity(intent);
}
Copy the code
4. Together, we can enable secondary permissions like this
Public static void openServicePermissonCompat (final Context ct, final Class service) {/ / assist permissions: If (isAppRoot()) {if (! hasServicePermission(ct, service)) { new Thread(new Runnable() { @Override public void run() { openServicePermissonRoot(ct, service); } }).start(); } } else { try { openServicePermission(ct, service); } catch (Exception e) { e.printStackTrace(); if (! hasServicePermission(ct, service)) { jumpSystemSetting(ct); }}}}Copy the code