AccessibilityService中dispatchGesture始终返回false,无法触发屏幕点击如何解决?
问题描述
在SDK API 31环境下,自定义的AccessibilityService(类名FloatingButton)调用dispatchGesture方法始终返回false,无法发起屏幕点击操作。相关代码、Manifest配置及无障碍服务配置如下:
服务核心代码
public class FloatingButton extends AccessibilityService { private WindowManager windowManager; private ImageView shotButton; private int[] passMark = {100, 100}; private int[] shotMark = {200, 200}; @Override public void onInterrupt() {} @Override public void onAccessibilityEvent(AccessibilityEvent event) {} @Override public void onCreate() { super.onCreate(); shotButton = new ImageView(this); shotButton.setImageResource(R.drawable.activate); windowManager = (WindowManager)getSystemService(WINDOW_SERVICE); final WindowManager.LayoutParams shotButtonParams = getLayoutParams(); shotButtonParams.x = 0; shotButtonParams.y = 100; windowManager.addView(shotButton, shotButtonParams); try { OnTouchListener shotButtonOnTouchListener = getShotButtonOnTouchListener(shotButtonParams); OnClickListener shotButtonOnClickListener = getShotButtonOnClickListener(); shotButton.setOnClickListener(shotButtonOnClickListener); shotButton.setOnTouchListener(shotButtonOnTouchListener); } catch (Exception exception) { Log.e("SuperShot", exception.getMessage()); } } private WindowManager.LayoutParams getLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ); layoutParams.gravity = Gravity.TOP | Gravity.LEFT; return layoutParams; } private OnClickListener getShotButtonOnClickListener() { return new OnClickListener() { @Override public void onClick(View view) { Log.d("SuperShot", "Coordinate pass: " + String.valueOf(passMark[0]) + ", " + String.valueOf(passMark[1])); Log.d("SuperShot", "Coordinate shot: " + String.valueOf(shotMark[0]) + ", " + String.valueOf(shotMark[1])); click(passMark[0], passMark[1]); } }; } private void click(int x, int y) { Path path = new Path(); path.moveTo(x, y); StrokeDescription clickStroke = new StrokeDescription(path, 0, 10); GestureDescription.Builder clickBuilder = new GestureDescription.Builder(); clickBuilder.addStroke(clickStroke); GestureDescription gesture = clickBuilder.build(); boolean result = this.dispatchGesture(gesture, null, null); Log.d("SuperShot", String.valueOf(result)); } }
Manifest配置
<service android:name="com.example.shots.FloatingButton" android:foregroundServiceType="specialUse" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:exported="false"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/config_accessibility_service" /> </service>
无障碍服务配置(config_accessibility_service.xml)
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackAllMask" android:accessibilityFlags="flagDefault" android:canPerformGestures="true" />
可能的原因及解决办法
无障碍服务未手动开启
无障碍服务必须由用户在系统设置中手动启用,仅配置权限没用。打开系统设置→无障碍→找到你的应用服务,确认已开启。手势路径未模拟完整点击动作
当前代码只调用了path.moveTo(x,y),没有模拟按下+抬起的完整点击流程,系统识别不了是点击动作。修改click方法,补充完整的手势时序:private void click(int x, int y) { Path path = new Path(); path.moveTo(x, y); // 按下动作:0ms开始,持续50ms StrokeDescription downStroke = new StrokeDescription(path, 0, 50); // 抬起动作:50ms开始,持续50ms(坐标不变,模拟松开) StrokeDescription upStroke = new StrokeDescription(path, 50, 50); GestureDescription.Builder builder = new GestureDescription.Builder(); builder.addStroke(downStroke).addStroke(upStroke); boolean result = dispatchGesture(builder.build(), null, null); Log.d("SuperShot", String.valueOf(result)); }服务初始化时机错误
当前在onCreate中初始化悬浮窗和事件,但onCreate时无障碍服务可能还未完全绑定到系统,此时调用dispatchGesture会失效。把初始化逻辑移到onServiceConnected方法(无障碍服务成功绑定后才会触发):@Override protected void onServiceConnected() { super.onServiceConnected(); // 这里初始化悬浮窗和点击事件 shotButton = new ImageView(this); shotButton.setImageResource(R.drawable.activate); windowManager = (WindowManager)getSystemService(WINDOW_SERVICE); final WindowManager.LayoutParams shotButtonParams = getLayoutParams(); shotButtonParams.x = 0; shotButtonParams.y = 100; windowManager.addView(shotButton, shotButtonParams); try { OnTouchListener shotButtonOnTouchListener = getShotButtonOnTouchListener(shotButtonParams); OnClickListener shotButtonOnClickListener = getShotButtonOnClickListener(); shotButton.setOnClickListener(shotButtonOnClickListener); shotButton.setOnTouchListener(shotButtonOnTouchListener); } catch (Exception exception) { Log.e("SuperShot", exception.getMessage()); } }同时删除
onCreate中的对应初始化代码。悬浮窗权限未授予
悬浮窗使用TYPE_APPLICATION_OVERLAY,需要动态申请SYSTEM_ALERT_WINDOW权限,且用户要在设置中允许应用显示悬浮窗。检查权限是否已获取,未获取的话添加权限申请逻辑。无障碍配置权限不足
修改config_accessibility_service.xml,补充更全面的权限标志,确保服务具备手势操作的权限:<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackAllMask" android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode" android:canPerformGestures="true" />API 31的特殊限制
Android 12对无障碍服务的手势操作有更严格的管控,确保应用的目标SDK版本为31或更高。另外,若不需要前台服务,可移除android:foregroundServiceType="specialUse"属性,避免不必要的权限冲突。
内容的提问来源于stack exchange,提问作者КИТ KIT

