如何检测向自身应用发送点击事件或查看其界面的其他应用?
检测外部应用的点击事件与界面查看行为
一、检测发送点击事件的应用包名
普通用户手动触发的点击事件来自系统输入框架,没有对应的"发送应用包名"——这类事件属于用户直接交互,并非由第三方应用发起。但如果是第三方应用通过模拟输入(如自动化脚本、无障碍服务、Instrumentation工具)注入的点击事件,可以通过以下方式追踪:
- 重写Activity的
dispatchTouchEvent方法,结合AppOpsManager检查注入权限:@Override public boolean dispatchTouchEvent(MotionEvent ev) { // 判断事件是否为外部注入(非用户直接触摸) if ((ev.getFlags() & MotionEvent.FLAG_FROM_SYSTEM) == 0) { AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE); // 检查拥有注入事件权限的应用 int mode = appOps.checkOpNoThrow(AppOpsManager.OP_INJECT_EVENTS, android.os.Process.myUid(), getPackageName()); if (mode != AppOpsManager.MODE_ALLOWED) { // 遍历已安装应用,排查拥有注入权限的应用 PackageManager pm = getPackageManager(); List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_META_DATA); for (ApplicationInfo app : apps) { int opMode = appOps.checkOpNoThrow(AppOpsManager.OP_INJECT_EVENTS, app.uid, app.packageName); if (opMode == AppOpsManager.MODE_ALLOWED) { Log.d("InjectSource", "可能的事件注入应用:" + app.packageName); } } } } return super.dispatchTouchEvent(ev); } - 补充:如果是无障碍服务发起的事件,可通过注册
AccessibilityService监听AccessibilityEvent,从中直接获取发起服务的应用包名;普通应用无法精准定位到具体注入事件的应用,只能通过权限排查缩小范围。
二、检测正在查看你应用界面的应用
这里指的是在你的应用界面之上叠加窗口的第三方应用(如悬浮窗、弹窗、画中画应用),可通过以下方法检测:
- 遍历系统窗口,判断外部应用窗口覆盖情况:
public String getTopOverlayPackage(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); List<WindowManager.LayoutParams> windows = wm.getWindowLayoutParams(); for (WindowManager.LayoutParams params : windows) { if (params.type == WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY) { String packageName = params.packageName; if (!packageName.equals(context.getPackageName())) { return packageName; } } } return null; } - Android 10及以上,结合
AppOpsManager排查拥有悬浮窗权限的应用:public List<String> getOverlayApps(Context context) { AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); PackageManager pm = context.getPackageManager(); List<String> overlayApps = new ArrayList<>(); List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_META_DATA); for (ApplicationInfo app : apps) { int mode = appOps.checkOpNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, app.uid, app.packageName); if (mode == AppOpsManager.MODE_ALLOWED && !app.packageName.equals(context.getPackageName())) { overlayApps.add(app.packageName); } } return overlayApps; } - 注意:获取窗口信息需要
android.permission.SYSTEM_ALERT_WINDOW权限,部分厂商可能限制普通应用的窗口访问权限;若需精准监听窗口变化,可注册AccessibilityService,通过TYPE_WINDOW_STATE_CHANGED事件获取当前顶层窗口的包名。
内容的提问来源于stack exchange,提问作者localacct
相关产品推荐
相关产品推荐

