针对 ShortX(及其它 Android 脚本环境)中遇到的“脚本运行多次产生多个重复窗口”的问题解决方案的技术:
1. 核心痛点:沙盒隔离
在 ShortX 等应用中,每次点击运行脚本都会创建一个全新的 JS Runtime(沙盒)。
 * 普通全局变量失效:脚本 A 定义的 var dialog 在脚本 B 运行阶段是 undefined* 内存引用丢失:无法通过 JS 逻辑判断上一个 Dialog 对象的状态,导致 dialog.show() 不断叠加,产生多个悬浮层。
2. 修复方案:物理视图标识 (Unique ID Tagging)
我们避开了不稳定的 JS 变量,转而利用 Android 系统自带的 View ID 机制:
 * 唯一性标记:在创建 Dialog 的根布局(Root View)时,手动为其设置一个硬编码的 ID(如 1008611)。这个 ID 存在于系统的 UI 视图树中,不随脚本沙盒的销毁而消失。
 * 反射级扫描:利用 Java 反射(Reflection)访问 Android 系统的 WindowManagerGlobal。这个类管理着当前应用进程中所有挂载到屏幕上的窗口视图。
 * 全局物理检测:
   * 脚本启动时,先去系统的 mViews 列表中遍历所有的根视图。
   * 检查这些视图中是否包含 ID1008611 的子视图。
3. 最终逻辑:检测即停止
**“非侵入式”**的运行逻辑:
| 场景 | 系统行为 | 脚本动作 |
|---|---|---|
| 首次运行 | 扫描 UI 树,未发现 ID 1008611 | 正常运行:创建窗口,设置 ID,显示 UI|
| 再次运行 | 扫描 UI 树,发现 ID 1008611 已存在 | 静默停止:在 Log 中提示“已在运行”,并立刻退出,不执行 UI 创建代码。 |
| 带参数运行 | 扫描 UI 树,发现 ID 1008611 | 数据先行:先将新任务写入 JSON,检测到窗口已存在后停止 UI 创建,由已存在的窗口在下次操作时刷新数据。 |
4. 关键技术点(避坑指南)
 * ID 选择:必须使用一个较大的、非系统的整数(避开 0-1),防止与系统控件 ID 冲突。
 * 权限声明:在 window.setType 时,必须使用 TYPE_APPLICATION_OVERLAYTYPE_SYSTEM_ALERT,这保证了窗口被挂载到全局视图层级中,方便被 WindowManagerGlobal 扫描到。
 * 异步兼容:在 Handler.post 的异步闭包内执行检测,确保检测环境与窗口创建环境在同一个主线程(UI Thread),提高判断准确度。
 
 
Back to Top