while(true){
try {
// 检查确定按钮
text('确定').click()
sleep(200)
} catch (e) {
}
try {
// 检查确认信息并支付按钮
text('确认信息并支付').click()
sleep(200)
} catch (e) {
}
try {
// 检查就是这家按钮
text('就是这家').click()
sleep(200)
} catch (e) {
}
try {
// 检查自提门店不存在或未营业提示
text('我知道了').click()
sleep(200)
} catch (e) {
}
try {
// 检查确认无误按钮
text('确认无误').click()
sleep(200)
} catch (e) {
}
log(1)
} 为什么脚本在执行到某个点击后会阻塞,直到停止运行才会执行阻塞后的操作然后结束
我想极快速的点击代码中的这几个元素,需要没有任何延时的那种,该用哪种点击方式
a = text('确定').findOnce()
log(a.bounds.centerX,a.bounds.centerY)
if(a){
click(a.bounds.centerX,a.bounds.centerY)
} 不能这么操作么
回答
脚本在执行到某个点击后会阻塞,直到停止运行才会执行后续操作的原因可能是该点击操作依赖某些条件才能完成。例如:
-
控件操作阻塞:
- 某些点击操作可能需要目标控件处于可交互状态(如
clickable
为true
)。如果控件暂时不可点击或被其他界面覆盖,脚本可能会等待控件变为可点击状态。 - 如果目标控件触发了耗时的操作(如弹出新页面、加载数据等),脚本可能因为等待这些操作完成而阻塞。
- 某些点击操作可能需要目标控件处于可交互状态(如
-
异步操作未完成:
- 脚本中的某些操作是异步的,比如
text('确定').click()
可能会触发一个动画或后台任务,脚本会在继续执行前等待这个任务完成。
- 脚本中的某些操作是异步的,比如
-
系统限制导致阻塞:
- 安卓系统的权限限制或者 Hamibot 的运行机制可能导致某些操作在特定情况下无法立即完成,从而导致阻塞。
-
异常未捕获完全:
- 虽然你使用了
try-catch
来处理异常,但如果某些异常没有被捕获或处理不完整,脚本可能停留在某处无法继续执行。
- 虽然你使用了
-
死循环问题:
- 你的代码中有一个
while(true)
循环,并且没有退出条件。如果在循环内部某个操作卡住,会导致整个脚本阻塞。
- 你的代码中有一个
解决方案
为了防止脚本阻塞,你可以尝试以下方法:
-
在每个操作后添加适当的延时,确保操作有足够时间完成:
text('确定').click(); sleep(1000); // 延时1秒,确保点击操作完成
-
确保控件存在后再进行操作,避免无效点击:
if (text('确定').exists()) { text('确定').click(); sleep(1000); }
-
检查是否有弹窗或其他干扰因素,优先处理这些情况。
-
添加超时机制,避免无限等待:
var startTime = new Date().getTime(); while (!text('确定').exists() && new Date().getTime() - startTime < 5000) { sleep(500); } if (text('确定').exists()) { text('确定').click(); } else { log("控件未出现,超时"); }
-
确保无障碍服务和相关权限已启用。
通过以上方法,可以有效减少脚本阻塞的可能性,提升脚本的稳定性。
补充回答 1
如果你希望极快速地点击代码中的元素,没有任何延时,并且不依赖控件查找的阻塞行为,你需要使用基于坐标的点击方式,并确保以下几点:
推荐方案:使用 Tap(x, y)
(需要 Root 权限)
这是目前唯一能够实现无延迟、异步点击的方式,适用于你已经知道目标控件坐标的情况。
// 示例代码:
while (true) {
Tap(x1, y1); // 快速点击“确定”
Tap(x2, y2); // 快速点击“确认信息并支付”
Tap(x3, y3); // 快速点击“就是这家”
Tap(x4, y4); // 快速点击“我知道了”
Tap(x5, y5); // 快速点击“确认无误”
}
注意:
Tap(x, y)
是非阻塞的,不会等待点击完成。- 该函数执行非常快,适合高频点击。
- 需要设备已 Root,并开启 Root 权限。
- 请提前用布局分析工具获取准确的点击坐标。
如果没有 Root 权限怎么办?
你可以尝试使用 click(x, y)
,但要注意:
- 它是同步操作,会等待大约 150ms 才继续执行脚本。
- 在安卓 7.0 及以上系统可用。
- 虽然不如
Tap()
快,但仍比控件查找点击快很多。
click(x, y);
不建议使用控件查找点击的原因
像 text('确定').click()
这类操作本质上会进行控件查找和匹配,这会导致:
- 查找耗时;
- 控件不存在时抛出异常或阻塞;
- 操作顺序不可控。
总结建议
点击方式 | 是否推荐 | 说明 |
---|---|---|
Tap(x, y) |
✅ 强烈推荐 | 极快、非阻塞,需 Root |
click(x, y) |
✅ 推荐 | 同步点击,速度较快,需安卓 7.0+ |
text(...).click() |
❌ 不推荐 | 控件查找慢,易阻塞 |
最佳实践示例(使用 Tap)
// 假设你已经获取到如下坐标
var coords = [
[x1, y1], // 确定
[x2, y2], // 确认信息并支付
[x3, y3], // 就是这家
[x4, y4], // 我知道了
[x5, y5], // 确认无误
];
while (true) {
coords.forEach(function(pos) {
Tap(pos[0], pos[1]);
});
}
补充回答 2
你写的代码逻辑是可行的,但在某些情况下会导致错误或无法执行。以下是你的代码:
a = text('确定').findOnce()
log(a.bounds.centerX, a.bounds.centerY)
if (a) {
click(a.bounds.centerX, a.bounds.centerY)
}
问题分析
-
变量
a
的类型可能为null
:- 如果当前界面上没有找到“确定”按钮,
text('确定').findOnce()
会返回null
。 - 此时访问
a.bounds
会抛出异常(TypeError: Cannot read property "bounds" from null
)。
- 如果当前界面上没有找到“确定”按钮,
-
判断语句的位置不对:
- 你在
log(...)
和访问a.bounds
之后才判断if (a)
,这已经导致了潜在的空指针错误。
- 你在
正确写法
你应该先判断控件是否存在,再进行操作和输出日志:
var a = text('确定').findOnce();
if (a) {
var bounds = a.bounds();
log(bounds.centerX(), bounds.centerY());
click(bounds.centerX(), bounds.centerY());
} else {
log("未找到控件");
}
✅ 这样可以避免在
a
为null
时访问其属性,确保脚本稳定运行。
延伸建议
- 如果你追求更快点击速度,可以将
click(x, y)
替换为Tap(x, y)
,但需要 Root 权限。 - 控件查找本身有一定耗时,如果你需要频繁点击,建议缓存坐标值或使用循环中加判断的方式。
完整示例:循环查找并点击
while (true) {
var a = text('确定').findOnce();
if (a) {
var bounds = a.bounds();
Tap(bounds.centerX(), bounds.centerY()); // 或 click(...)
}
sleep(200); // 避免 CPU 占用过高
}