// Redmi K20 (MIUI12.0.4) 专用最终版脚本
console.show();
toast("最终版脚本启动");

// 应用包名配置(用户提供)
const PACKAGE_NAMES = {
CLEAN: "com.android.xqqnews", // 清理应用
XHS: "com.xingin.xhs", // 小红书
XINGTU: "com.lemon.photoeditor", // 醒图(标准包名)
SETTINGS: "com.android.settings" // 设置
};

// 强制启动函数(解决MIUI限制)
function forceLaunch(packageName, timeout = 5000) {
try {
console.log("强制启动: " + packageName);
const intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setPackage(packageName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
context.startActivity(intent);

// 等待启动完成
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
  if (currentPackage() === packageName) {
    console.log("启动成功");
    return true;
  }
  sleep(500);
}
console.error("启动超时");
return false;

} catch (e) {
console.error("启动失败: " + e.message);
return false;
}
}

// 等待元素出现
function waitForElement(text, timeout = 20) {
const startTime = Date.now();
while (Date.now() - startTime < timeout * 1000) {
if (textExists(text)) return true;
sleep(1000);
}
return false;
}

// 主循环
while (true) {
try {
// 阶段1: 清理应用
if (!forceLaunch(PACKAGE_NAMES.CLEAN)) {
toast("清理应用启动失败");
exit();
}
sleep(20000);
home();

// 阶段2: 小红书操作
if (!forceLaunch(PACKAGE_NAMES.XHS)) {
  toast("小红书启动失败");
  exit();
}
if (waitForElement("去登录")) {
  click(text("去登录"));
}
sleep(3000);
home();

// 阶段3: 醒图应用
if (!forceLaunch(PACKAGE_NAMES.XINGTU)) {
  toast("醒图启动失败");
  exit();
}
sleep(20000);

// 下滑找到小红书项目
for (let i = 0; i < 3; i++) {
  scrollDown();
  sleep(1000);
  if (waitForElement("小红书")) {
    click(text("小红书"));
    sleep(20000);
    
    // 点击通道一
    if (waitForElement("通道一")) {
      click(text("通道一"));
      sleep(5000);
      
      // 处理登录状态
      if (currentPackage() !== PACKAGE_NAMES.XINGTU) {
        back();
        if (waitForElement("小红书")) {
          click(text("小红书"));
          sleep(20000);
          if (waitForElement("复扫")) {
            click(text("复扫"));
            if (waitForElement("第一个")) {
              click(text("第一个"));
            }
          }
        }
      }
      
      // 小红书刷新操作
      if (currentPackage() === PACKAGE_NAMES.XHS) {
        // 主页刷新
        for (let j = 0; j < 3; j++) {
          scrollUp();
          scrollDown();
          sleep(1000);
        }
        
        // 消息页面
        if (waitForElement("消息")) {
          click(text("消息"));
          for (let j = 0; j < 3; j++) {
            scrollUp();
            scrollDown();
            sleep(1000);
          }
        }
        
        // 我的页面
        if (waitForElement("我的")) {
          click(text("我的"));
          for (let j = 0; j < 3; j++) {
            scrollUp();
            scrollDown();
            sleep(1000);
          }
        }
      }
    }
    break;
  }
}
home();

// 阶段4: 备份操作
if (!forceLaunch(PACKAGE_NAMES.SETTINGS)) {
  toast("设置启动失败");
  exit();
}
if (waitForElement("我的设备")) {
  click(text("我的设备"));
  scrollDown();
  if (waitForElement("备份及恢复")) {
    click(text("备份及恢复"));
    if (waitForElement("U盘备份恢复")) {
      click(text("U盘备份恢复"));
      
      // 取消全选
      if (waitForElement("全选")) click(text("全选"));
      
      // 勾选小红书
      scrollDown();
      if (waitForElement("小红书")) {
        if (!isChecked(text("小红书"))) click(text("小红书"));
      }
      
      // 立即备份
      if (waitForElement("立即备份")) {
        click(text("立即备份"));
        if (waitForElement("完成", 300)) click(text("完成"));
      }
    }
  }
}
home();

// 阶段5: 通知栏处理
expandNotification();
if (waitForElement("备份完成")) {
  click(text("备份完成"));
  if (waitForElement("完成")) click(text("完成"));
}
collapseNotification();

// 阶段6: 清理操作
if (!forceLaunch(PACKAGE_NAMES.CLEAN)) {
  toast("清理应用启动失败");
  exit();
}
if (waitForElement("停止")) {
  click(text("停止"));
  if (waitForElement("确定")) click(text("确定"));
}
if (waitForElement("开始清理")) click(text("开始清理"));

// 等待重启
sleep(60000);

} catch (e) {
console.error("执行错误: " + e.stack);
toast("错误: " + e.message);
sleep(5000); // 错误后延迟重试
}
}

这个为啥无法运行

wenkcvptwr · 3 小时前

回答

Hamibot AI
1
· 3 小时前

文档地址 https://docs.hamibot.com/

你的脚本无法运行,可能由以下几个常见原因导致。以下是针对你提供的脚本和 Redmi K20(MIUI 12.0.4)环境的详细分析与修改建议:


1. 缺少必要权限

Hamibot 脚本必须在开启「无障碍服务」的前提下才能运行。

解决方法:

  • 打开 Hamibot 应用 → 点击左上角菜单 → 进入「无障碍服务」→ 启用 Hamibot。
  • 若已开启但仍然失败,请尝试重启设备或手动在系统设置中授权:

    设置 → 无障碍 → 已下载的服务 → 启用 Hamibot

🔴 注意:MIUI 对后台服务限制较严,即使开启了无障碍,也可能被系统自动杀掉。建议将 Hamibot 加入“电池优化”白名单,并锁定应用不被清理。


2. context, Intent 等原生 Android API 不可用

你在脚本中使用了如下代码:

const intent = new Intent(Intent.ACTION_MAIN);
...
context.startActivity(intent);

这是调用 Android 原生 Java API 的方式,但在 Hamibot 的 Rhino 脚本环境中,默认不支持直接访问 contextIntent,除非你通过 runtime 反射获取。

错误表现:

  • 报错:ReferenceError: "Intent" is not defined
  • 或者 context is undefined

✅ 正确做法:使用 app.launch() 启动应用

Hamibot 提供了更简单的封装函数来启动应用:

// 替换 forceLaunch 函数为以下版本
function forceLaunch(packageName, appName) {
  console.log("尝试启动: " + packageName);
  if (app.launch(packageName)) {
    sleep(3000); // 给予启动时间
    return true;
  } else {
    // 尝试通过名称启动
    if (appName && app.launchApp(appName)) {
      sleep(3000);
      return true;
    }
    console.error("启动失败:" + packageName);
    return false;
  }
}

然后调用时传入包名即可,例如:

forceLaunch(PACKAGE_NAMES.XHS, "小红书");

⚠️ 不推荐直接操作 Intentcontext,除非你知道如何用 Java 反射机制安全调用。


3. textExists(), text(), click() 等控件操作需依赖「无障碍服务」且控件可识别

你使用了如:

if (textExists("去登录")) {
  click(text("去登录"));
}

这需要满足两个条件:

  1. 当前界面确实存在该文本;
  2. 无障碍服务能读取到该 UI 控件。

问题点:

  • textExists(str) 是正确用法;
  • click(text("xxx")) 写法有误!应改为 text("xxx").findOne().click()

✅ 修改建议:

// ❌ 错误写法
click(text("去登录"));

// ✅ 正确写法
if (text("去登录").exists()) {
  text("去登录").findOne().click();
}

同理,所有 click(text(...)) 都要改成 .findOne().click()


4. currentPackage() 函数不存在

你在判断当前应用时用了:

if (currentPackage() === packageName)

这个函数在 Hamibot 中并不存在。

✅ 正确函数是:currentPackage() 应为 currentApp().packageName

// 获取当前应用信息
function getCurrentPackage() {
  return currentApp().packageName;
}

// 使用示例:
if (getCurrentPackage() === packageName) {
  console.log("已进入目标应用");
}

5. scrollUp(), scrollDown() 并非标准 API

Hamibot 没有内置 scrollUp()scrollDown() 函数。

✅ 正确滚动方式是使用 scrollForward()scrollBackward()

// 向上滑动(前进方向)
scrollForward();

// 向下滑动(回退方向)
scrollBackward();

如果你希望模拟手势滑动,也可以使用 swipe()

// 从屏幕中间向下 swipe,模拟下滑
swipe(device.width / 2, device.height * 0.7, device.width / 2,
ℹ️ 本回答由 AI 生成,内容仅供参考