YYPOST群发软件 发表于 2026-7-6 06:22:17

agent代理模式功能小结

agent代理模式功能小结



// AIWROK agent 代理 API 完整示例
// 展示常用的代理操作

print.log("===== agent 代理 API 示例 =====");

// ========== 1. 绝对坐标点击 agent.click(x, y) ==========
print.log("\n--- 1. 绝对坐标点击 agent.click(x, y) ---");
print.log("说明:使用屏幕绝对像素坐标进行点击");
print.log("适用:已知精确坐标的场景");

var 屏幕宽 = screen.getScreenWidth();
var 屏幕高 = screen.getScreenHeight();
print.log("当前屏幕:" + 屏幕宽 + " x " + 屏幕高);

agent.click(100, 100);
print.log("✓ 已点击坐标 (100, 100)");

var 中心X = Math.floor(屏幕宽 / 2);
var 中心Y = Math.floor(屏幕高 / 2);
agent.click(中心X, 中心Y);
print.log("✓ 已点击屏幕中心 (" + 中心X + ", " + 中心Y + ")");

// ========== 2. 百分比坐标点击 agent.clickPercent(px, py) ==========
print.log("\n--- 2. 百分比坐标点击 agent.clickPercent(px, py) ---");
print.log("说明:使用百分比坐标(0.0-1.0),自动适配不同屏幕");
print.log("适用:需要在不同分辨率设备上运行的脚本");

agent.clickPercent(0.5, 0.5);
print.log("✓ 已点击屏幕中心 (50%, 50%)");

agent.clickPercent(0.9, 0.9);
print.log("✓ 已点击屏幕右下区域 (90%, 90%)");

agent.clickPercent(0.5, 0.1);
print.log("✓ 已点击屏幕顶部中间 (50%, 10%)");

// ========== 3. 查找文字并点击 ==========
print.log("\n--- 3. 查找文字并点击 ---");
print.log("说明:通过 agent.shell() 执行 uiautomator dump 获取 UI XML");
print.log("注意:agent.getXml() 返回对象而非字符串,获取UI() 返回字符串");

function 执行Shell(命令) {
    var 结果 = agent.shell(命令);
    if (!结果) return "";
   
    var 结果字符串 = "";
    if (typeof 结果 === "string") {
      结果字符串 = 结果;
    } else if (结果.toString) {
      结果字符串 = 结果.toString();
    } else {
      结果字符串 = "" + 结果;
    }
   
    var startIdx = -1;
    if (typeof 结果字符串.indexOf === "function") {
      startIdx = 结果字符串.indexOf("successMsg:");
    }
   
    if (startIdx !== -1) {
      var afterSuccess = 结果字符串.substring(startIdx + 11);
      var errorIdx = afterSuccess.indexOf(",errorMsg:");
      if (errorIdx !== -1) {
            var content = afterSuccess.substring(0, errorIdx);
            var endMarker = content.indexOf("UI hierchary dumped to:");
            if (endMarker !== -1) {
                content = content.substring(0, endMarker);
            }
            return "" + content.trim();
      }
      return "" + afterSuccess.trim();
    }
   
    return "" + 结果字符串;
}

function 获取UI() {
    var 临时文件 = "/sdcard/ui_dump.xml";
    agent.shell("uiautomator dump --compressed " + 临时文件 + " 2>/dev/null");
    var 结果 = agent.shell("cat " + 临时文件);
   
    if (!结果) return "";
   
    var 结果字符串 = "";
    if (typeof 结果 === "string") {
      结果字符串 = 结果;
    } else if (结果.toString) {
      结果字符串 = 结果.toString();
    } else {
      结果字符串 = "" + 结果;
    }
   
    var startIdx = -1;
    if (typeof 结果字符串.indexOf === "function") {
      startIdx = 结果字符串.indexOf("successMsg:");
    }
   
    var content = "";
    if (startIdx !== -1) {
      var afterSuccess = 结果字符串.substring(startIdx + 11);
      var errorIdx = afterSuccess.indexOf(",errorMsg:");
      if (errorIdx !== -1) {
            content = afterSuccess.substring(0, errorIdx);
            var endMarker = content.indexOf("UI hierchary dumped to:");
            if (endMarker !== -1) {
                content = content.substring(0, endMarker);
            }
      } else {
            content = afterSuccess;
      }
      content = content.trim();
    } else {
      content = 结果字符串;
    }
   
    return "" + content;
}

var xml = 获取UI();
if (xml.indexOf("网络和互联网") !== -1) {
    print.log("找到【网络和互联网】节点");

    var 文字索引 = xml.indexOf("网络和互联网");
    var 后面 = xml.substring(文字索引);
    var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);

    if (m) {
      var left = parseInt(m);
      var top = parseInt(m);
      var right = parseInt(m);
      var bottom = parseInt(m);
      var centerX = (left + right) / 2;
      var centerY = (top + bottom) / 2;

      print.log("节点范围:[" + left + "," + top + "][" + right + "," + bottom + "]");
      print.log("计算中心点:(" + centerX + ", " + centerY + ")");

      agent.click(centerX, centerY);
      print.log("✓ 已点击【网络和互联网】");
    } else {
      print.log("⚠ 未找到节点坐标");
    }
} else {
    print.log("当前页面未找到【网络和互联网】");
}

print.log("\n💡 点击提示:");
print.log("- agent.click(x,y) 适合固定坐标或从节点计算出的坐标");
print.log("- agent.clickPercent(px,py) 适合跨设备兼容的场景");
print.log("- 两者可以配合 auto.findText() 实现智能定位点击");

// ========== 4. 滑动操作 ==========
print.log("\n--- 4. 滑动操作 ---");
agent.swip(540, 2800, 540, 800, 500);// 从下往上滑动
print.log("✓ 滑动完成");

// ========== 5. AI 算法滑动(模拟手动)==========
print.log("\n--- 5. AI 算法滑动 ---");
agent.swipAI(540, 2800, 540, 800);// 更自然的滑动
print.log("✓ AI 滑动完成");

// ========== 6. 按键操作 ==========
print.log("\n--- 6. 按键操作 ---");
agent.back();      // 返回键
print.log("✓ 按下返回键");

agent.home();      // Home 键
print.log("✓ 按下 Home 键");

agent.home2();   // Home 键(另一种实现方式)
print.log("✓ 发送 Home 按键(home2)");

agent.recents();   // 最近任务键
print.log("✓ 按下最近任务键");

// agent.power();   // 开机键(移到脚本最后,避免提前关屏)
// print.log("✓ 按下开机键");

agent.keyPress(4); // 发送按键码 4(返回键,等同于 back())
print.log("✓ 通过 keyPress 发送返回键");

agent.keyPress(3); // 发送按键码 3(Home 键,等同于 home())
print.log("✓ 通过 keyPress 发送 Home 键");

// ========== 7. 输入文本 ==========
print.log("\n--- 7. 输入文本 ---");
agent.input("Hello World");// 输入文字
print.log("✓ 已输入文本");

// ========== 8. 获取节点信息 ==========
print.log("\n--- 8. 获取节点信息 ---");
print.log("注意:agent.getXml() 返回对象,获取UI() 返回字符串");

var xml2 = 获取UI();
print.log("XML 长度:" + xml2.length);

function 查找所有包含文字的节点(xml, 文字) {
    var 结果 = [];
    var 位置 = 0;
    while (true) {
      var 索引 = xml.indexOf('text="' + 文字 + '"', 位置);
      if (索引 === -1) break;

      var 后面 = xml.substring(索引);
      var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
      if (m) {
            结果.push({
                left: parseInt(m),
                top: parseInt(m),
                right: parseInt(m),
                bottom: parseInt(m),
                centerX: (parseInt(m) + parseInt(m)) / 2,
                centerY: (parseInt(m) + parseInt(m)) / 2
            });
      }
      位置 = 索引 + 10;
    }
    return 结果;
}

var nodes = 查找所有包含文字的节点(xml2, "同意");
print.log("找到包含'同意'的节点数:" + nodes.length);

function 查找所有节点JSON(xml) {
    var 结果 = [];
    var 节点列表 = [];
    var classIndex = xml.indexOf('class="');

    while (classIndex !== -1) {
      var 后面 = xml.substring(classIndex);
      var boundsM = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
      var textM = 后面.match(/text="([^"]*)"/);
      var idM = 后面.match(/resource-id="([^"]*)"/);

      if (boundsM) {
            var 节点 = {
                class: "",
                left: parseInt(boundsM),
                top: parseInt(boundsM),
                right: parseInt(boundsM),
                bottom: parseInt(boundsM),
                text: textM ? textM : "",
                resourceId: idM ? idM : ""
            };
            结果.push(节点);
      }
      classIndex = xml.indexOf('class="', classIndex + 7);
    }
    return 结果;
}

var jsonNodes = 查找所有节点JSON(xml2);
print.log("JSON 节点数:" + jsonNodes.length);

print.log("\n💡 提示:agent.findNodesByTextMatches/Contains/Json 在实际设备上不存在");
print.log("请使用 agent.shell('uiautomator dump ...') + 自定义函数解析");

// ========== 9. 截图 ==========
print.log("\n--- 9. 屏幕截图 ---");
print.log("说明:agent.screenShot() 在部分设备上不存在,使用 shell 命令截图");

var 截图路径 = "/sdcard/screenshot_" + Date.now() + ".png";
agent.shell("screencap -p " + 截图路径);
print.log("✓ 截图已保存到:" + 截图路径);

var 检查文件 = 执行Shell("ls -l " + 截图路径);
if (检查文件) {
    print.log("✓ 截图文件信息:" + 检查文件);
}

// ========== 10. Shell 命令 ==========
print.log("\n--- 10. 执行 Shell 命令 ---");
var result = 执行Shell("uiautomator dump --compressed /proc/self/fd/1 2>/dev/null");
print.log("✓ Shell 命令执行完成");

// ========== 11. 触摸事件(高级)==========
print.log("\n--- 11. 触摸事件 ---");
print.log("说明:touchDown 可用,但 touchMove/touchUp/touchUpUp 在部分设备上不存在");
print.log("注意:实际测试中,仅 touchDown 可调用,其他方法报错");

agent.touchDown(540, 1800);   // 按下(x, y)- 已验证可用
sleep.millisecond(毫秒 = 100);
// agent.touchMove(540, 1900);   // 移动 - 报错:Can't find method
// sleep.millisecond(毫秒 = 100);
// agent.touchUp(540, 1900);   // 抬起 - 报错:Can't find method
print.log("✓ touchDown 执行完成(touchMove/touchUp/touchUpUp 在当前设备上不可用)");

// touchUpUp 与 touchUp 类似,但同样在当前设备上不可用
// agent.touchUpUp(540, 1900);   // 触摸抬起 - 报错:Can't find method
print.log("✓ touchUpUp 在当前设备上不可用");

// ========== 12. 检查代理状态 ==========
print.log("\n--- 12. 代理状态 ---");
var isOpen = agent.isOpen();
print.log("代理是否开启:" + isOpen);

// ========== 13. 开启代理模式 ==========
print.log("\n--- 13. 开启代理模式 agent.start() ---");
print.log("说明:开启代理模式,手机必须 root 或使用 PC_IDE 的 adb 连接");
print.log("返回值:boolean,成功返回 true");

var 开启结果 = agent.start();
print.log("开启代理模式结果:" + 开启结果);

var 再次检查 = agent.isOpen();
print.log("开启后代理状态:" + 再次检查);

// ========== 14. 四个方向滑动 ==========
print.log("\n--- 14. 四个方向滑动 ---");
print.log("说明:通过交换起止坐标实现上/下/左/右四个方向的滑动");

var 中X = Math.floor(屏幕宽 / 2);
var 中Y = Math.floor(屏幕高 / 2);
var 偏移 = 800;

// 向上滑动(内容向上滚动,看下方内容)
agent.swip(中X, 中Y + 偏移, 中X, 中Y - 偏移, 500);
print.log("✓ 向上滑动完成");

// 向下滑动(内容向下滚动,看上方内容)
agent.swip(中X, 中Y - 偏移, 中X, 中Y + 偏移, 500);
print.log("✓ 向下滑动完成");

// 向左滑动(查看右侧内容,如翻页)
agent.swip(中X + 偏移, 中Y, 中X - 偏移, 中Y, 500);
print.log("✓ 向左滑动完成");

// 向右滑动(查看左侧内容,如返回上一页)
agent.swip(中X - 偏移, 中Y, 中X + 偏移, 中Y, 500);
print.log("✓ 向右滑动完成");

// ========== 15. 长按操作 ==========
print.log("\n--- 15. 长按操作 ---");
print.log("说明:由于 touchUp 在当前设备上不可用,使用 swip 实现长按");

// agent.touchDown(540, 1800);
// sleep.second(秒 = 2);
// agent.touchUp(540, 1800);// 报错:Can't find method
// print.log("✓ 长按 (540, 1800) 持续 2 秒完成");

// 长按用 swip 实现(起点终点几乎相同,时间长)
agent.swip(540, 1800, 541, 1801, 2000);
print.log("✓ 通过 swip 实现长按完成(持续 2 秒)");

// ========== 15. 双击操作 ==========
print.log("\n--- 15. 双击操作 ---");
print.log("说明:两次连续 click,间隔 100-200ms 模拟双击");

agent.click(540, 1800);
sleep.millisecond(毫秒 = 150);
agent.click(540, 1800);
print.log("✓ 双击 (540, 1800) 完成");

// ========== 16. 剪贴板操作与粘贴 ==========
print.log("\n--- 16. 剪贴板操作与粘贴 ---");
print.log("说明:先写入剪贴板,再通过按键粘贴到当前输入框");

var 待输入文本 = "这是要粘贴的中文内容";

// 方式1:通过 Clipboard.copy() 设置剪贴板
Clipboard.copy(待输入文本);
sleep.millisecond(毫秒 = 300);

// 方式2:通过 shell service call clipboard(双保险,部分设备 Clipboard API 失效时使用)
agent.shell("service call clipboard 3 i32 1 s16 '" + 待输入文本 + "' i32 0");
sleep.millisecond(毫秒 = 300);

// 触发粘贴:KEYCODE_PASTE (279)
agent.shell("input keyevent 279");
sleep.second(秒 = 1);
print.log("✓ 已通过 KEYCODE_PASTE 粘贴文本");

// 备用方式:Ctrl+V 组合键(KEYCODE_V=50 + META_CTRL_ON=0x1000)
// agent.shell("input keyevent 50 --meta 0x1000");

// ========== 17. 启动应用 ==========
print.log("\n--- 17. 启动应用 ---");
print.log("说明:使用 app.openApp() 启动指定包名的应用");

var 抖音包名 = "com.ss.android.ugc.aweme";
var 小红书包名 = "com.xingin.xhs";
var 微信包名 = "com.tencent.mm";
var 头条极速版包名 = "com.ss.android.article.lite";
var 设置包名 = "com.android.settings";

print.log("常用应用包名:");
print.log("- 抖音:" + 抖音包名);
print.log("- 小红书:" + 小红书包名);
print.log("- 微信:" + 微信包名);
print.log("- 头条极速版:" + 头条极速版包名);
print.log("- 设置:" + 设置包名);

// 启动抖音(示例,注释掉避免实际执行)
// app.openApp(抖音包名);
// sleep.second(秒 = 5);
// print.log("✓ 已启动抖音");

print.log("💡 提示:启动后可配合 agent.clickPercent() 进行界面操作");

// ========== 18. 通过 resourceId 查找节点 ==========
print.log("\n--- 18. 通过 resourceId 查找节点 ---");
print.log("说明:从 XML 中通过 resource-id 属性查找节点坐标");

function 通过ID查找节点(xml, resourceId) {
    var 索引 = xml.indexOf('resource-id="' + resourceId + '"');
    if (索引 === -1) {
      return null;
    }
    var 后面 = xml.substring(索引);
    var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
    if (!m) {
      return null;
    }
    var left = parseInt(m);
    var top = parseInt(m);
    var right = parseInt(m);
    var bottom = parseInt(m);
    return {
      left: left,
      top: top,
      right: right,
      bottom: bottom,
      centerX: (left + right) / 2,
      centerY: (top + bottom) / 2,
      width: right - left,
      height: bottom - top
    };
}

var xmlForId = 获取UI();

function 获取当前包名(xml) {
    var m = xml.match(/package="([^"]+)"/);
    return m ? m : "";
}

var 当前包名 = 获取当前包名(xmlForId);
print.log("当前前台应用包名:" + 当前包名);

var 节点ById = 通过ID查找节点(xmlForId, "android:id/title");
if (节点ById) {
    print.log("✓ 找到标题节点,中心点:(" + 节点ById.centerX + ", " + 节点ById.centerY + ")");
    print.log("尺寸:" + 节点ById.width + " x " + 节点ById.height);
} else {
    var 所有Ids = [];
    var idIndex = xmlForId.indexOf('resource-id="');
    while (idIndex !== -1) {
      var endIndex = xmlForId.indexOf('"', idIndex + 13);
      if (endIndex !== -1) {
            var id = xmlForId.substring(idIndex + 13, endIndex);
            if (id && !id.match(/^com\.android/) && !所有Ids) {
                所有Ids.push(id);
                所有Ids = true;
            }
      }
      idIndex = xmlForId.indexOf('resource-id="', idIndex + 13);
    }
    print.log("⚠ 未找到指定 resourceId,当前界面可用 resource-id 列表(前10个):");
    for (var i = 0; i < Math.min(10, 所有Ids.length); i++) {
      print.log("- " + 所有Ids);
    }
}

// ========== 19. 通过 className 查找所有节点 ==========
print.log("\n--- 19. 通过 className 查找所有节点 ---");
print.log("说明:查找界面上所有指定 className 的节点(如所有按钮/输入框)");

function 通过Class查找所有节点(xml, className) {
    var 结果 = [];
    var 查找值 = 'class="' + className + '"';
    var 位置 = 0;

    while (true) {
      var 索引 = xml.indexOf(查找值, 位置);
      if (索引 === -1) break;

      var 后面 = xml.substring(索引);
      var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
      if (m) {
            var left = parseInt(m);
            var top = parseInt(m);
            var right = parseInt(m);
            var bottom = parseInt(m);
            结果.push({
                left: left,
                top: top,
                right: right,
                bottom: bottom,
                centerX: (left + right) / 2,
                centerY: (top + bottom) / 2,
                width: right - left,
                height: bottom - top
            });
      }
      位置 = 索引 + 查找值.length;
    }
    return 结果;
}

var xmlForClass = 获取UI();

// 查找所有 EditText 输入框
var 输入框列表 = 通过Class查找所有节点(xmlForClass, "android.widget.EditText");
print.log("找到 EditText 输入框数量:" + 输入框列表.length);
for (var i = 0; i < 输入框列表.length; i++) {
    var 框 = 输入框列表;
    print.log("输入框[" + i + "] 中心(" + 框.centerX + ", " + 框.centerY + ") 尺寸 " + 框.width + "x" + 框.height);
}

// 查找所有 Button 按钮
var 按钮列表 = 通过Class查找所有节点(xmlForClass, "android.widget.Button");
print.log("找到 Button 按钮数量:" + 按钮列表.length);

// ========== 20. 通过 content-desc 查找节点 ==========
print.log("\n--- 20. 通过 content-desc 查找节点 ---");
print.log("说明:通过无障碍描述查找节点(适合图标按钮,如返回/加号)");

function 通过ContentDesc查找节点(xml, desc) {
    var 索引 = xml.indexOf('content-desc="' + desc + '"');
    if (索引 === -1) {
      return null;
    }
    var 后面 = xml.substring(索引);
    var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
    if (!m) {
      return null;
    }
    var left = parseInt(m);
    var top = parseInt(m);
    var right = parseInt(m);
    var bottom = parseInt(m);
    return {
      left: left,
      top: top,
      right: right,
      bottom: bottom,
      centerX: (left + right) / 2,
      centerY: (top + bottom) / 2
    };
}

var xmlForDesc = 获取UI();
var 返回节点 = 通过ContentDesc查找节点(xmlForDesc, "返回");
if (返回节点) {
    print.log("✓ 找到【返回】按钮,中心点:(" + 返回节点.centerX + ", " + 返回节点.centerY + ")");
} else {
    print.log("⚠ 当前页面未找到 content-desc=返回 的节点");
}

// 常见的 content-desc 值:返回、发布、加号、+、搜索、菜单、更多

// ========== 21. 通过 hint 查找输入框 ==========
print.log("\n--- 21. 通过 hint 查找输入框 ---");
print.log("说明:输入框未输入内容时通常显示 hint 提示文字(如标题/正文)");

function 通过Hint查找输入框(xml, hint) {
    var 索引 = xml.indexOf('hint="' + hint + '"');
    if (索引 === -1) {
      // 尝试变体
      var 变体 = ;
      for (var i = 0; i < 变体.length; i++) {
            索引 = xml.indexOf('hint="' + 变体 + '"');
            if (索引 !== -1) {
                hint = 变体;
                break;
            }
      }
    }
    if (索引 === -1) {
      return null;
    }
    var 后面 = xml.substring(索引);
    var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
    if (!m) {
      return null;
    }
    return {
      centerX: (parseInt(m) + parseInt(m)) / 2,
      centerY: (parseInt(m) + parseInt(m)) / 2,
      hint: hint
    };
}

var xmlForHint = 获取UI();
var 标题框 = 通过Hint查找输入框(xmlForHint, "标题");
if (标题框) {
    print.log("✓ 找到标题输入框(hint=" + 标题框.hint + ")中心点:(" + 标题框.centerX + ", " + 标题框.centerY + ")");
} else {
    print.log("⚠ 未找到标题输入框");
}

// ========== 22. 等待节点出现 ==========
print.log("\n--- 22. 等待节点出现 ---");
print.log("说明:循环检测 XML,直到出现目标文字或超时(适合页面加载等待)");

function 等待文字出现(目标文字, 超时秒) {
    var 开始时间 = Date.now();
    var 超时毫秒 = 超时秒 * 1000;

    while (Date.now() - 开始时间 < 超时毫秒) {
      try {
            var xml = 获取UI();
            if (xml.indexOf(目标文字) !== -1) {
                var 已等待 = Math.floor((Date.now() - 开始时间) / 1000);
                print.log("✓ 在 " + 已等待 + " 秒后检测到【" + 目标文字 + "】");
                return true;
            }
      } catch (e) {
            print.log("⚠ 获取 XML 出错:" + e.message);
      }
      sleep.second(秒 = 1);
    }
    print.log("✗ 等待 " + 超时秒 + " 秒后未出现【" + 目标文字 + "】");
    return false;
}

// 示例:等待"下一步"按钮出现(最多 10 秒)
// var 找到 = 等待文字出现("下一步", 10);
// if (找到) {
//   agent.click(节点.centerX, 节点.centerY);
// }
print.log("&#128161; 提示:循环等待 + 节点查找 + 点击 = 稳定的自动化流程");

// ========== 23. 实用 Shell 命令大全 ==========
print.log("\n--- 23. 实用 Shell 命令大全 ---");
print.log("说明:通过 agent.shell() 执行各种系统命令");

// 1. 获取当前界面 XML(最常用)
var uiXml = 执行Shell("uiautomator dump --compressed /proc/self/fd/1 2>/dev/null");
print.log("✓ 1. 获取 UI XML,长度:" + uiXml.length);

// 2. 模拟按键事件(input keyevent)
agent.shell("input keyevent 4");      // KEYCODE_BACK 返回键
agent.shell("input keyevent 3");       // KEYCODE_HOME Home键
agent.shell("input keyevent 24");   // KEYCODE_VOLUME_UP 音量加
agent.shell("input keyevent 25");   // KEYCODE_VOLUME_DOWN 音量减
agent.shell("input keyevent 26");   // KEYCODE_POWER 电源键
agent.shell("input keyevent 279");    // KEYCODE_PASTE 粘贴
print.log("✓ 2. 模拟按键事件完成");

// 3. 启动应用(am start)
// agent.shell("am start -n com.xingin.xhs/.activity.SplashActivity");
// agent.shell("monkey -p com.xingin.xhs 1");// 通过 monkey 启动
print.log("✓ 3. am start / monkey 启动应用");

// 4. 强制停止应用
// agent.shell("am force-stop com.xingin.xhs");
print.log("✓ 4. am force-stop 强制停止应用");

// 5. 设置剪贴板(service call clipboard)
agent.shell("service call clipboard 3 i32 1 s16 '剪贴板内容' i32 0");
print.log("✓ 5. service call clipboard 设置剪贴板");

// 6. 长按滑动(input swipe,可模拟长按)
// agent.shell("input swipe 540 1800 541 1801 2000");
print.log("✓ 6. input swipe 模拟长按");

// 7. 输入文字(input text,仅支持 ASCII)
agent.shell("input text 'Hello'");
print.log("✓ 7. input text 输入 ASCII 文字");

// 8. 获取系统属性
var 属性值 = 执行Shell("getprop ro.product.model");
print.log("✓ 8. 设备型号:" + 属性值);

// ========== 24. 截图保存到文件 ==========
print.log("\n--- 24. 截图保存到文件 ---");
print.log("说明:使用 screencap 命令截图,agent.screenShot() 在部分设备上不存在");

var 截图路径 = "/sdcard/screenshot_" + Date.now() + ".png";
agent.shell("screencap -p " + 截图路径);
print.log("✓ 截图已保存到:" + 截图路径);

var 文件检查 = 执行Shell("ls -l " + 截图路径);
if (文件检查) {
    var 大小信息 = 文件检查;
    print.log("✓ 截图文件信息:" + 大小信息);
}
print.log("&#128161; 配合 file API 持久化截图,便于后续 OCR 找字或上传");

// ========== 25. 综合实战:智能查找并点击流程 ==========
print.log("\n--- 25. 综合实战:智能查找并点击流程 ---");
print.log("说明:循环查找节点 → 计算 → 点击 → 验证 → 重试");

function 智能查找并点击(目标文字, 超时秒) {
    var 开始时间 = Date.now();
    var 超时毫秒 = 超时秒 * 1000;
    var 尝试次数 = 0;

    while (Date.now() - 开始时间 < 超时毫秒) {
      尝试次数++;
      try {
            var xml = 获取UI();

            // 检查目标文字是否存在
            if (xml.indexOf(目标文字) === -1) {
                sleep.second(秒 = 1);
                continue;
            }

            // 通过 bounds 正则提取坐标
            var 文字索引 = xml.indexOf(目标文字);
            var 后面 = xml.substring(文字索引);
            var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);

            if (m) {
                var left = parseInt(m);
                var top = parseInt(m);
                var right = parseInt(m);
                var bottom = parseInt(m);
                var cx = (left + right) / 2;
                var cy = (top + bottom) / 2;

                agent.click(cx, cy);
                print.log("✓ 第 " + 尝试次数 + " 次尝试:已点击【" + 目标文字 + "】(" + cx + ", " + cy + ")");

                // 点击后等待并验证
                sleep.second(秒 = 1);
                var xml2 = 获取UI();
                if (xml2.indexOf(目标文字) === -1) {
                  print.log("✓ 验证成功:目标已消失");
                  return true;
                } else {
                  print.log("⚠ 目标仍存在,可能点击未生效,重试...");
                }
            }
      } catch (e) {
            print.log("⚠ 第 " + 尝试次数 + " 次尝试出错:" + e.message);
      }
      sleep.second(秒 = 1);
    }

    print.log("✗ 超时 " + 超时秒 + " 秒,共尝试 " + 尝试次数 + " 次未成功");
    return false;
}

// 示例调用(注释避免实际执行)
// 智能查找并点击("同意", 10);
// 智能查找并点击("下一步", 15);
// 智能查找并点击("发布", 10);
print.log("&#128161; 此函数封装了完整的查找→点击→验证→重试流程,可直接复用");

// ========== 26. 错误处理与重试机制 ==========
print.log("\n--- 26. 错误处理与重试机制 ---");
print.log("说明:使用 try-catch 包裹关键操作,失败时自动重试");

function 带重试的操作(操作函数, 操作名, 最大重试) {
    最大重试 = 最大重试 || 3;
    for (var i = 1; i <= 最大重试; i++) {
      try {
            print.log("第 " + i + "/" + 最大重试 + " 次尝试 " + 操作名);
            var 结果 = 操作函数();
            if (结果) {
                print.log("✓ " + 操作名 + " 成功");
                return true;
            }
      } catch (e) {
            print.log("⚠ 第 " + i + " 次出错:" + e.message);
      }
      if (i < 最大重试) {
            sleep.second(秒 = 1);
      }
    }
    print.log("✗ " + 操作名 + " 失败,已重试 " + 最大重试 + " 次");
    return false;
}

// 示例:带重试的点击操作
// 带重试的操作(function() {
//   var xml = 获取UI();
//   if (xml.indexOf("下一步") === -1) return false;
//   // ... 查找并点击
//   return true;
// }, "点击下一步", 3);

print.log("&#128161; try-catch + 重试机制可大幅提升脚本稳定性");

// ========== 27. 应用管理与切换 ==========
print.log("\n--- 27. 应用管理与切换 ---");
print.log("说明:启动、切换、关闭应用的常用方法");

// 启动应用
// app.openApp("com.xingin.xhs");
// sleep.second(秒 = 5);

// 通过 shell 启动指定 Activity(更精确)
// agent.shell("am start -n com.xingin.xhs/.activity.SplashActivity");

// 通过包名启动(monkey 方式,更通用)
// agent.shell("monkey -p com.xingin.xhs 1");

// 强制停止应用
// agent.shell("am force-stop com.xingin.xhs");

// 切换到最近任务
// agent.recents();
// sleep.second(秒 = 1);
// agent.clickPercent(0.5, 0.5);// 点击第一个任务

// 查看当前前台应用
var 当前应用 = 执行Shell("dumpsys window | grep mCurrentFocus");
var 当前应用长度 = typeof 当前应用.length === "function" ? 当前应用.length() : (当前应用.length || 0);
var 当前应用显示 = 当前应用.substring(0, Math.min(当前应用长度, 100));
print.log("当前前台应用信息:" + 当前应用显示);

print.log("&#128161; 应用管理流程:启动 → 操作 → 验证 → 关闭");

// ========== 28. 电源键操作(最后执行)==========
print.log("\n--- 28. 电源键操作 ---");
print.log("说明:移到最后执行,避免提前关屏影响后续操作");
agent.power();   // 开机键
print.log("✓ 按下开机键(关屏)");

print.log("\n===== 示例结束 =====");


页: [1]
查看完整版本: agent代理模式功能小结