我的无障碍服务定义为:
class ClickService : AccessibilityService() {
// Pretend the necessary methods are overrided
override fun onCreate() {
super.onCreate()
val binding = TODO() // Pretend we have a view binding here
binding.clickButton.setOnClickListener {
click(100, 200)
}
}
private fun click(x: Int, y: Int) {
val gesture = GestureDescription.Builder().addStroke(
GestureDescription.StrokeDescription(
Path().apply { moveTo(x.toFloat(), y.toFloat()) },
0, // startTime
1, // duration
)
)
dispatchGesture(gesture.build(), null, null)
}
}
AndroidManifest.xml
<service
android:name=".ui.ClickService"
android:exported="false"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:canPerformGestures="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
然后,ClickService
作为前台服务从我的 MainActivity
启动。
运行此命令(并授予应用程序其可访问权限)使
dispatchGesture
返回 true,但它永远不会模拟其单击。这是为什么?是什么让这个默默失败?
我对为什么这不起作用的想法是:
dispatchGesture
在 UI 线程之外运行。但是:
canPerformGestures
设置为 true
。除了启用应用程序的可访问性(已经有)之外,我没有看到任何其他所需的权限。setOnClickListener
的回调已经在 UI 线程中运行,所以我不需要做任何特殊的事情来使 dispatchGesture
从同一线程运行。为什么
dispatchGesture
返回 true,但实际上并没有点击任何东西?
答案其实很简单。对我来说,我没有正确定义
AndroidManifest
。android:canPerformGestures
设置为 true,但不是 android 从中读取它的位置。
这是
AndroidManifest.xml
中更新的服务(注意元数据元素):
<service
android:name=".ui.ClickService"
android:exported="false"
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/config_accessibility_service" />
</service>
在
res/xml/config_accessibility_service.xml
中创建一个文件(或任何您想要的名称,但请确保它与您的 AndroidManifest
中匹配:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:canPerformGestures="true" />