Android M及以上版本实现显示触摸操作的技术方案咨询
解决Android M+无法通过Settings.System开启触摸显示的替代方案
我之前也踩过这个坑,Android 6.0(API 23)之后谷歌大幅收紧了系统安全设置的权限,Settings.System.putInt(context.getContentResolver(), "show_touches", 1)这类修改私有安全设置的操作,只有系统签名的应用或者持有特定系统权限的应用才能执行。哪怕把targetSdk降到22,在高版本系统上也会逐渐被限制,完全不符合你要使用高版本新特性的需求。下面给你几个可行的替代方案:
方案1:利用辅助功能(AccessibilityService)实现全局触摸显示
这是普通APP能实现全局触摸显示的唯一合法途径——辅助功能拥有监听系统级触摸事件的权限,能绕过普通APP的权限限制:
- 创建自定义AccessibilityService子类,重写
onAccessibilityEvent方法监听触摸事件; - 通过WindowManager添加一个全局悬浮视图,在触摸事件触发时,实时更新悬浮视图的位置并绘制触摸点(比如半透明圆圈);
- 在Manifest中注册这个Service,配置对应的辅助功能声明,引导用户在系统设置中开启你的服务。
核心代码片段示例:
public class TouchShowAccessibilityService extends AccessibilityService { private WindowManager windowManager; private View touchPointView; private WindowManager.LayoutParams params; @Override public void onCreate() { super.onCreate(); windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); touchPointView = new View(this); // 自定义触摸点样式,比如一个半透明的圆形drawable touchPointView.setBackgroundResource(R.drawable.touch_indicator); params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT ); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { // 处理触摸按下、移动等事件,更新触摸点位置 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) { int x = (int) event.getX(); int y = (int) event.getY(); params.x = x - touchPointView.getWidth()/2; params.y = y - touchPointView.getHeight()/2; windowManager.updateViewLayout(touchPointView, params); } } @Override public void onInterrupt() {} }
注意:用户需要手动在系统设置的「辅助功能」里开启你的服务,你可以在APP内做引导跳转,提升用户体验。
方案2:仅在自身APP内显示触摸操作(无需系统权限)
如果你的需求只是在自己的APP内显示触摸轨迹,那完全不需要依赖系统权限,直接在APP层面处理即可:
- 在BaseActivity中重写
dispatchTouchEvent方法,监听所有触摸事件; - 创建一个自定义OverlayView,添加到Activity的DecorView中;
- 在触摸事件触发时,在OverlayView上绘制触摸点或轨迹。
核心代码示例:
public class BaseActivity extends AppCompatActivity { private TouchOverlayView touchOverlayView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); touchOverlayView = new TouchOverlayView(this); getWindow().getDecorView().addView(touchOverlayView); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { touchOverlayView.updateTouchPosition(ev); return super.dispatchTouchEvent(ev); } private static class TouchOverlayView extends View { private float touchX, touchY; private Paint paint; public TouchOverlayView(Context context) { super(context); paint = new Paint(); paint.setColor(Color.parseColor("#80FF4081")); paint.setStyle(Paint.Style.FILL); } public void updateTouchPosition(MotionEvent ev) { touchX = ev.getX(); touchY = ev.getY(); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(touchX, touchY, 25, paint); } } }
这个方案不需要用户开启任何系统权限,只在你的APP内生效,适合仅需自身APP内调试或演示的场景。
关于你尝试过的悬浮层方案的优化
如果你之前的悬浮层方案存在触摸事件被拦截、显示不流畅等问题,可以结合上面的辅助功能方案:用AccessibilityService监听系统触摸事件,再通过悬浮层更新显示——这样既不会干扰正常的触摸操作,又能实现全局触摸显示的效果。
总结一下:如果需要全局触摸显示,辅助功能是目前普通APP唯一可行的合法方案;如果只需要自身APP内显示,直接在APP内处理触摸事件并绘制即可。
内容的提问来源于stack exchange,提问作者kklmarvelmedia
相关产品推荐
相关产品推荐

