现象描述
同一套 Hamibot 脚本,使用id("o_u")匹配微信会话红点控件:
1、在 Hamibot 软件内手动点击运行脚本:无障碍正常捕获控件,红点识别、整套自动化流程全部正常工作;
2、由我方自研 APP 下发任务唤起 Hamibot 执行一模一样的脚本:脚本可正常启动、读取本地配置文件、正常打印运行日志,唯独 id 控件查询永久返回空数组,无法抓取页面任何控件,无报错、无崩溃。
我方已做的代码优化操作(均无效)
脚本头部添加 auto.setFlags(["findOnUiThread"]);
每次查找控件前重新执行 auto () 重连无障碍服务、刷新 auto.root 窗口根节点;
脚本启动时主动拉起 Hamibot 前台页面,尝试绑定窗口上下文环境。
设备权限全部放行
Hamibot:无障碍、悬浮窗、自启动、后台常驻、电池优化白名单、后台活动不受限制;
自研 APP、微信全部加入系统省电白名单,禁止系统休眠查杀进程。
硬性要求
项目不允许更换 OCR、固定坐标识别红点,必须依赖控件 ID 查找方式实现功能。
咨询问题
1、第三方 APP 唤起 Hamibot 后台 Service 执行脚本时,会丢失无障碍窗口绑定上下文,造成 id 选择器读取控件树失效,是否属于 Hamibot 固有机制限制?是否存在参数、配置、API 能够让后台拉起的脚本拥有和前台手动运行一致的无障碍捕获环境?
2、官方有没有支持第三方外部 APP 稳定调用执行脚本的标准方案?我方 APP 需要配合修改哪些调用逻辑、权限配置才能解决该问题?
3、后台模式运行脚本,强制获取最新屏幕视图快照的官方可行写法是什么?
回答
根据你的描述,这是 Android 无障碍服务(AccessibilityService)的工作机制导致的,并非 Hamibot 特有的限制,而是 Android 系统对无障碍服务获取窗口控件树的硬性要求:无障碍服务只有在当前前台窗口可被捕获时,才能获取到控件树信息。当你的自研 APP 通过后台 Service 唤起 Hamibot 执行脚本时,Hamibot 自身并没有前台 Activity,系统认为它处于后台,此时无障碍服务无法获取到微信(或其他前台应用)的窗口控件树,所以 id("o_u") 等选择器永远返回空数组。
下面针对你的三个问题逐一解答。
1. 第三方 APP 唤起 Hamibot 后台 Service 执行脚本时,丢失无障碍窗口绑定上下文,是否属于固有机制限制?有无参数或 API 能让后台脚本拥有与前台手动运行一致的捕获环境?
是固有机制限制,没有参数或 API 可以绕过。
Android 无障碍服务的设计原则是:只有拥有前台窗口上下文(或者说当前有可见 Activity)的服务才能稳定获取窗口节点信息。当 Hamibot 完全在后台执行脚本时,系统会认为它没有与用户交互的界面,因此不会为它提供当前前台窗口的控件树。auto.setFlags(["findOnUiThread"])、auto() 重连、auto.root 刷新等操作,都是基于无障碍服务已经成功绑定窗口上下文的前提下生效的,如果根本没有窗口上下文,这些操作不会产生任何效果。
唯一可行的解决方案是:在脚本执行查找控件前,确保目标应用(微信)处于前台,并且 Hamibot 的无障碍服务能够捕获到该窗口。
具体做法是:在脚本中显式调用 app.launchApp("微信") 或 app.startActivity(...) 将微信切换到前台,然后等待界面加载(如 sleep(2000)),再进行控件查找。这样,无障碍服务看到的当前前台窗口就是微信,就能正常捕获 id("o_u") 控件了。
2. 官方有没有支持第三方外部 APP 稳定调用执行脚本的标准方案?我方 APP 需要配合修改哪些调用逻辑、权限配置才能解决该问题?
官方没有提供专为后台调用设计的“免前台”方案。
Hamibot 的脚本执行本身不依赖前台 Activity,但无障碍控件的捕获必须依赖前台窗口,这是 Android 系统层面的限制,不是 Hamibot 能通过权限或配置解决的。
如果你希望从自研 APP 触发脚本后稳定获取微信控件,你需要修改调用逻辑:
- 在自研 APP 唤醒 Hamibot 脚本之前,先确保微信已经在前台(例如通过
Intent将微信切换到前台,或者直接让用户手动打开微信后,再触发任务)。 - 脚本内部第一件事就是调用
app.launchApp("微信"),确保微信处于前台,避免因系统调度导致微信被切换到后台。 - 权限方面:你已经放的权限(无障碍、悬浮窗、自启动、后台常驻、电池优化等)是正确的,但仅靠权限无法解决窗口上下文问题,必须配合前台切换。
更稳定的实践方案:使用 Hamibot 的“定时任务”或“云端触发”功能,让脚本按照预设条件自动执行,这时用户通常是正常使用手机,微信在前台的概率很高,点击控件会自然成功。如果一定要由外部 APP 触发,强烈建议在触发前让微信进入前台,并在脚本中做二次确认。
3. 后台模式运行脚本,强制获取最新屏幕视图快照的官方可行写法是什么?
没有“后台强制获取屏幕视图快照”的官方写法。
Android 无障碍服务不允许在后台无窗口上下文时获取任何窗口的控件树,这是系统安全机制,任何 API 都无法绕过(除非使用 root 权限截屏并 OCR,但你的项目禁止 OCR)。
如果你需要在脚本中刷新控件树,正确的做法仍然是:先确保目标应用在前台,再使用 auto.root 或 auto.refresh() 获取最新节点。示例代码:
// 文档地址 https://docs.hamibot.com/
// 确保微信在前台
app.launchApp("微信");
sleep(2000); // 等待界面加载
// 刷新窗口根节点(可选,但建议)
auto.root.refresh();
// 查找控件
var redDot = id("o_u").findOnce();
if (redDot) {
toast("找到红点");
} else {
toast("未找到红点");
}
再次强调,auto.root.refresh() 只有在无障碍服务已经绑定了前台窗口时才有效。如果微信不在前台,无论如何刷新,auto.root 都是空的。
总结:你的问题本质是后台脚本无法获取前台控件树,唯一的解决路径是让微信在脚本执行时处于前台。请在你的脚本中加上 app.launchApp("微信"),并在自研 APP 唤起 Hamibot 前确保微信已在前台,即可彻底解决控件查询失败的问题。