Step‑by‑Step Guide to Android AccessibilityService for UI Automation
This article introduces Android's AccessibilityService, explains its fundamentals, shows how to create, register, and configure the service, demonstrates common techniques such as node searching and interaction, and provides a complete Kotlin example that automatically logs into WeChat on Windows/Mac.
This tutorial begins with a brief introduction to Android automation, emphasizing that all Android automation frameworks rely on adb and the AccessibilityService.
It then explains why using AccessibilityService allows you to package automation scripts into an APK, making distribution easier compared to PC‑based adb scripts.
0x1. Introduction
The author greets readers and repeats the core premise: all Android automation functions are built on adb and AccessibilityService.
0x2. AccessibilityService Overview
Official Android documentation describes AccessibilityService as a service that provides UI enhancements for users with disabilities, and developers can create their own services.
It can assist users who cannot fully interact with the device, such as when driving or in noisy environments.
The service essentially enables an app to control other apps (click, scroll, input, etc.).
0x3. Basic Usage of AccessibilityService
AccessibilityService is a subclass of Service . When the user enables the service, the system calls onServiceConnected() ; when the service is disabled or the process is killed, disableSelf() is invoked.
① Create a custom AccessibilityService
Extend AccessibilityService and override onInterrupt() and onAccessibilityEvent() :
import android.accessibilityservice.AccessibilityService
import android.util.Log
import android.view.accessibility.AccessibilityEvent
class JumpAdAccessibilityService : AccessibilityService() {
val TAG = javaClass.simpleName
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
Log.d(TAG, "onAccessibilityEvent:$event")
}
override fun onInterrupt() {
Log.d(TAG, "onInterrupt")
}
}The two overridden methods are mandatory.
onInterrupt() – called when the service is interrupted.
onAccessibilityEvent() – called for each received AccessibilityEvent (e.g., notifications, UI changes).
② Register the Service
Add a <service> entry in AndroidManifest.xml :
<service
android:name=".JumpAdAccessibilityService"
android:exported="false"
android:label="跳过广告哈哈哈哈"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>Tip: the permission ensures only the system can bind the service; the label is shown in the accessibility settings UI.
③ Configure Event Listening
You can configure the service either dynamically in code (via onServiceConnected() ) or statically with an XML meta‑data file.
Dynamic configuration
override fun onServiceConnected() {
val serviceInfo = AccessibilityServiceInfo().apply {
eventTypes = AccessibilityEvent.TYPES_ALL_MASK
feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
flags = AccessibilityServiceInfo.DEFAULT
packageNames = arrayOf("com.tencent.mm") // monitor WeChat
notificationTimeout = 10
}
setServiceInfo(serviceInfo)
}Static configuration
Create res/xml/accessible_service_config_jump_ad.xml :
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_desc"
android:notificationTimeout="100"
android:packageNames="com.tencent.mm"
android:settingsActivity="cn.coderpig.jumpad.MainActivity" />Static configuration offers more options, while dynamic configuration is more flexible.
④ Enable the Service
After installing the app, enable the service via Settings → Accessibility → your app. The system will prompt for permission.
0x4. Common Tricks
Check whether the service is enabled.
Find nodes using AccessibilityEvent.getSource() or AccessibilityService.getRootInActiveWindow() .
Search nodes by text ( findAccessibilityNodeInfosByText() ) or view ID ( findAccessibilityNodeInfosByViewId() ).
Interact with nodes using performAction() (click, long‑click, scroll, input).
Execute global actions with performGlobalAction() (back, home, etc.).
① Check Service Status
fun Context.isAccessibilitySettingsOn(clazz: Class
): Boolean {
var enabled = false
try {
enabled = Settings.Secure.getInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED) == 1
} catch (e: Settings.SettingNotFoundException) { e.printStackTrace() }
if (enabled) {
val setting = Settings.Secure.getString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
setting?.let {
val splitter = SimpleStringSplitter(':')
splitter.setString(it)
while (splitter.hasNext()) {
if (splitter.next().equals("${packageName}/${clazz.canonicalName}", true)) return true
}
}
}
return false
}Call this method in onResume() to guide the user to the accessibility settings page if needed:
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))② Node Searching
Use AccessibilityEvent.getSource() or getRootInActiveWindow() to obtain the current AccessibilityNodeInfo , then search by text or view ID.
③ Node Interaction
// Click
fun AccessibilityNodeInfo.click() = performAction(AccessibilityNodeInfo.ACTION_CLICK)
// Long click
fun AccessibilityNodeInfo.longClick() = performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK)
// Scroll forward
fun AccessibilityNodeInfo.scrollForward() = performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
// Input text
fun AccessibilityNodeInfo.input(content: String) = performAction(
AccessibilityNodeInfo.ACTION_SET_TEXT,
Bundle().apply { putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, content) }
)④ Global Interaction
performGlobalAction(GLOBAL_ACTION_BACK) // Back button
performGlobalAction(GLOBAL_ACTION_HOME) // Home button0x5. Simple Case: Automatic WeChat Login on Windows/Mac
The author builds a minimal app that monitors WeChat login windows (event type TYPE_WINDOW_STATE_CHANGED with class ExtDeviceWXLoginUI ) and automatically clicks the login button using the node‑search and click utilities described above.
Key steps:
Detect whether the AccessibilityService is enabled.
Configure the service to listen to all events for the WeChat package.
In onAccessibilityEvent() , filter for TYPE_WINDOW_STATE_CHANGED and the target class name.
Locate the login button either by text containing "登录" or by its unique view ID, then invoke click() .
The result is an instant automatic login without user interaction.
0x6. Conclusion
The article covered the basics of AccessibilityService, common tricks, and a concrete example. Future topics will include a WeChat zombie‑friend detection tool.
References
Official documentation: "Create your own AccessibilityService".
AccessibilityService introductory guides.
Various community notes on AccessibilityService.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.