// ==================== 配置参数(根据实际情况修改)====================
const CONFIG = {
// 抢购时间(格式:"时:分:秒",如 "10:00:00",建议提前 1-2 秒)
BUY_TIME: "10:00:00",
// 农行 APP 包名(无需修改,主流版本通用)
ABC_PACKAGE: "com.abchina.mobilebank",
// 洗车券相关关键词(可根据 APP 内显示调整)
COUPON_KEYWORDS: ["1元洗车", "洗车券", "1元洗车权益"],
// 抢购按钮关键词(可根据按钮文字调整)
BUY_BUTTON_KEYWORDS: ["立即抢购", "秒杀", "抢券"],
// 重试次数(抢券失败后自动重试,避免网络延迟)
RETRY_COUNT: 3,
// 点击偏移量(避免点击同一位置被判定为机器人,单位:像素)
CLICK_OFFSET: 5
};
// ==================== 工具函数 ====================
/**
- 格式化时间为 "时:分:秒"
*/
function formatTime(date) {
const h = date.getHours().toString().padStart(2, "0");
const m = date.getMinutes().toString().padStart(2, "0");
const s = date.getSeconds().toString().padStart(2, "0");
return${h}:${m}:${s};
}
/**
- 等待指定毫秒数
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
- 随机偏移点击(防机器人检测)
*/
async function randomClick(x, y) {
const offsetX = Math.floor(Math.random() * CONFIG.CLICK_OFFSET * 2) - CONFIG.CLICK_OFFSET;
const offsetY = Math.floor(Math.random() * CONFIG.CLICK_OFFSET * 2) - CONFIG.CLICK_OFFSET;
const finalX = Math.max(0, Math.min(device.width - 1, x + offsetX));
const finalY = Math.max(0, Math.min(device.height - 1, y + offsetY));
await click(finalX, finalY);
console.log(随机点击位置:(${finalX}, ${finalY}));
}
/**
- 查找并点击包含关键词的控件
- @param {string[]} keywords - 关键词数组
- @param {number} timeout - 查找超时时间(毫秒)
- @returns {boolean} 是否找到并点击
*/
async function findAndClick(keywords, timeout = 3000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
for (const keyword of keywords) {
const widgets = id("").textContains(keyword).find();
if (widgets.length > 0) {
const target = widgets[0]; // 优先选择第一个匹配控件
const bounds = target.bounds();
await randomClick(bounds.centerX(), bounds.centerY());
console.log(找到关键词「${keyword}」,已点击);
return true;
}
}
await sleep(100); // 每 100ms 查找一次
}
console.log(超时未找到关键词:${keywords.join("、")});
return false;
}
/**
- 处理弹窗(关闭提示框、广告等)
*/
async function handlePopups() {
// 常见弹窗关闭关键词
const closeKeywords = ["关闭", "取消", "知道了", "稍后"];
await findAndClick(closeKeywords, 1000);
}
// ==================== 核心抢购逻辑 ====================
async function startGrabCoupon() {
try {
console.log("===== 开始执行 1 元洗车券抢购脚本 =====");
console.log(配置参数:${JSON.stringify(CONFIG)});
// 1. 检查设备权限
if (!device.isRooted() && !auto.serviceRunning()) {
toast("请开启无障碍服务后重试!");
console.error("无障碍服务未开启");
return;
}
// 2. 打开农行 APP
console.log("正在打开农行 APP...");
app.startActivity({
packageName: CONFIG.ABC_PACKAGE,
action: "android.intent.action.MAIN"
});
await sleep(5000); // 等待 APP 加载完成(根据手机性能调整)
// 3. 等待抢购时间
const targetTime = new Date();
const [h, m, s] = CONFIG.BUY_TIME.split(":").map(Number);
targetTime.setHours(h, m, s, 0);
const now = new Date();
if (now < targetTime) {
const waitTime = targetTime - now;
console.log(`当前时间:${formatTime(now)},抢购时间:${CONFIG.BUY_TIME}`);
console.log(`需等待 ${Math.floor(waitTime / 1000)} 秒...`);
toast(`等待抢购时间,剩余 ${Math.floor(waitTime / 1000)} 秒`);
// 提前 2 秒唤醒屏幕(防止息屏)
await sleep(waitTime - 2000);
device.wakeUp(); // 唤醒屏幕
await sleep(2000);
}
// 4. 定位洗车券入口(循环查找,兼容多入口)
console.log("正在查找洗车券入口...");
let enterSuccess = false;
for (let i = 0; i < 2; i++) { // 最多尝试 2 次(防止首次未找到)
enterSuccess = await findAndClick(CONFIG.COUPON_KEYWORDS, 3000);
if (enterSuccess) break;
await swipe(device.width / 2, device.height * 0.8, device.width / 2, device.height * 0.3, 500); // 向上滑动(查找更多入口)
await sleep(1000);
}
if (!enterSuccess) {
toast("未找到洗车券入口,请检查关键词或 APP 页面!");
console.error("未找到洗车券入口");
return;
}
await sleep(2000); // 等待页面加载
// 5. 执行抢购(带重试机制)
let buySuccess = false;
for (let i = 0; i < CONFIG.RETRY_COUNT; i++) {
console.log(`第 ${i + 1} 次尝试抢购...`);
handlePopups(); // 先关闭可能的弹窗
buySuccess = await findAndClick(CONFIG.BUY_BUTTON_KEYWORDS, 1000);
if (buySuccess) {
toast("抢购点击成功!请手动确认订单~");
console.log("抢购点击成功,等待订单确认");
await sleep(3000);
// 尝试点击"确认"按钮(如果有订单确认步骤)
await findAndClick(["确认", "提交订单"], 2000);
break;
}
// 抢购失败,刷新页面(向下滑动刷新)
await swipe(device.width / 2, device.height * 0.3, device.width / 2, device.height * 0.8, 500);
await sleep(1000);
}
if (!buySuccess) {
toast("抢购失败,请检查网络或券已售罄!");
console.error("抢购失败,重试次数用尽");
}
console.log("===== 脚本执行结束 =====");
} catch (error) {
console.error("脚本执行出错:", error);
toast(脚本出错:${error.message});
}
}
回答
你提供的代码是一个用于抢购1元洗车券的脚本,适用于Hamibot平台。以下是对你代码的一些建议和说明:
1. 配置参数
BUY_TIME:设置抢购时间,建议提前1-2秒,确保在目标时间开始前触发。ABC_PACKAGE:农行APP的包名,无需修改。COUPON_KEYWORDS:用于查找洗车券入口的关键词,可以根据实际APP界面调整。BUY_BUTTON_KEYWORDS:用于查找抢购按钮的关键词,根据按钮文字调整。RETRY_COUNT:抢购失败后的重试次数,避免因网络延迟导致的失败。CLICK_OFFSET:点击偏移量,防止被判定为机器人。
2. 工具函数
formatTime:格式化时间为"时:分:秒"。sleep:等待指定毫秒数。randomClick:随机偏移点击,防机器人检测。findAndClick:查找并点击包含关键词的控件。handlePopups:处理弹窗(关闭提示框、广告等)。
3. 核心抢购逻辑
- 检查设备权限:确保无障碍服务已开启。
- 打开农行APP:启动农行APP并等待加载完成。
- 等待抢购时间:计算抢购时间并等待。
- 定位洗车券入口:循环查找洗车券入口,兼容多入口。
- 执行抢购:带重试机制,尝试抢购并处理可能的弹窗。
4. 注意事项
- 确保设备已开启无障碍服务和后台弹窗权限。
- 根据实际APP界面调整关键词,例如
COUPON_KEYWORDS和BUY_BUTTON_KEYWORDS。 - 如果抢购失败,可以尝试增加重试次数或调整等待时间。
- 注意不要频繁操作,以免被系统判定为异常行为。
如果你有其他问题或需要进一步的帮助,请随时告诉我!