注册 登录
发贴工具
查看: 6|回复: 0
打印 上一主题 下一主题

[24小时收录超级好的网站] agent代理模式功能小结

[复制链接]

2576

主题

2624

帖子

1万

积分

积分
15632
跳转到指定楼层
楼主


agent代理模式功能小结


agent代理模式功能小结 群发软件发帖工具

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

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

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

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

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

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

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

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

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

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

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

  31. function 执行Shell(命令) {
  32.     var 结果 = agent.shell(命令);
  33.     if (!结果) return "";
  34.    
  35.     var 结果字符串 = "";
  36.     if (typeof 结果 === "string") {
  37.         结果字符串 = 结果;
  38.     } else if (结果.toString) {
  39.         结果字符串 = 结果.toString();
  40.     } else {
  41.         结果字符串 = "" + 结果;
  42.     }
  43.    
  44.     var startIdx = -1;
  45.     if (typeof 结果字符串.indexOf === "function") {
  46.         startIdx = 结果字符串.indexOf("successMsg:");
  47.     }
  48.    
  49.     if (startIdx !== -1) {
  50.         var afterSuccess = 结果字符串.substring(startIdx + 11);
  51.         var errorIdx = afterSuccess.indexOf(",errorMsg:");
  52.         if (errorIdx !== -1) {
  53.             var content = afterSuccess.substring(0, errorIdx);
  54.             var endMarker = content.indexOf("UI hierchary dumped to:");
  55.             if (endMarker !== -1) {
  56.                 content = content.substring(0, endMarker);
  57.             }
  58.             return "" + content.trim();
  59.         }
  60.         return "" + afterSuccess.trim();
  61.     }
  62.    
  63.     return "" + 结果字符串;
  64. }

  65. function 获取UI() {
  66.     var 临时文件 = "/sdcard/ui_dump.xml";
  67.     agent.shell("uiautomator dump --compressed " + 临时文件 + " 2>/dev/null");
  68.     var 结果 = agent.shell("cat " + 临时文件);
  69.    
  70.     if (!结果) return "";
  71.    
  72.     var 结果字符串 = "";
  73.     if (typeof 结果 === "string") {
  74.         结果字符串 = 结果;
  75.     } else if (结果.toString) {
  76.         结果字符串 = 结果.toString();
  77.     } else {
  78.         结果字符串 = "" + 结果;
  79.     }
  80.    
  81.     var startIdx = -1;
  82.     if (typeof 结果字符串.indexOf === "function") {
  83.         startIdx = 结果字符串.indexOf("successMsg:");
  84.     }
  85.    
  86.     var content = "";
  87.     if (startIdx !== -1) {
  88.         var afterSuccess = 结果字符串.substring(startIdx + 11);
  89.         var errorIdx = afterSuccess.indexOf(",errorMsg:");
  90.         if (errorIdx !== -1) {
  91.             content = afterSuccess.substring(0, errorIdx);
  92.             var endMarker = content.indexOf("UI hierchary dumped to:");
  93.             if (endMarker !== -1) {
  94.                 content = content.substring(0, endMarker);
  95.             }
  96.         } else {
  97.             content = afterSuccess;
  98.         }
  99.         content = content.trim();
  100.     } else {
  101.         content = 结果字符串;
  102.     }
  103.    
  104.     return "" + content;
  105. }

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

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

  112.     if (m) {
  113.         var left = parseInt(m[1]);
  114.         var top = parseInt(m[2]);
  115.         var right = parseInt(m[3]);
  116.         var bottom = parseInt(m[4]);
  117.         var centerX = (left + right) / 2;
  118.         var centerY = (top + bottom) / 2;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  172.         var 后面 = xml.substring(索引);
  173.         var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  174.         if (m) {
  175.             结果.push({
  176.                 left: parseInt(m[1]),
  177.                 top: parseInt(m[2]),
  178.                 right: parseInt(m[3]),
  179.                 bottom: parseInt(m[4]),
  180.                 centerX: (parseInt(m[1]) + parseInt(m[3])) / 2,
  181.                 centerY: (parseInt(m[2]) + parseInt(m[4])) / 2
  182.             });
  183.         }
  184.         位置 = 索引 + 10;
  185.     }
  186.     return 结果;
  187. }

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

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

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

  199.         if (boundsM) {
  200.             var 节点 = {
  201.                 class: "",
  202.                 left: parseInt(boundsM[1]),
  203.                 top: parseInt(boundsM[2]),
  204.                 right: parseInt(boundsM[3]),
  205.                 bottom: parseInt(boundsM[4]),
  206.                 text: textM ? textM[1] : "",
  207.                 resourceId: idM ? idM[1] : ""
  208.             };
  209.             结果.push(节点);
  210.         }
  211.         classIndex = xml.indexOf('class="', classIndex + 7);
  212.     }
  213.     return 结果;
  214. }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  331. function 通过ID查找节点(xml, resourceId) {
  332.     var 索引 = xml.indexOf('resource-id="' + resourceId + '"');
  333.     if (索引 === -1) {
  334.         return null;
  335.     }
  336.     var 后面 = xml.substring(索引);
  337.     var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  338.     if (!m) {
  339.         return null;
  340.     }
  341.     var left = parseInt(m[1]);
  342.     var top = parseInt(m[2]);
  343.     var right = parseInt(m[3]);
  344.     var bottom = parseInt(m[4]);
  345.     return {
  346.         left: left,
  347.         top: top,
  348.         right: right,
  349.         bottom: bottom,
  350.         centerX: (left + right) / 2,
  351.         centerY: (top + bottom) / 2,
  352.         width: right - left,
  353.         height: bottom - top
  354.     };
  355. }

  356. var xmlForId = 获取UI();

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

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

  363. var 节点ById = 通过ID查找节点(xmlForId, "android:id/title");
  364. if (节点ById) {
  365.     print.log("✓ 找到标题节点,中心点:(" + 节点ById.centerX + ", " + 节点ById.centerY + ")");
  366.     print.log("  尺寸:" + 节点ById.width + " x " + 节点ById.height);
  367. } else {
  368.     var 所有Ids = [];
  369.     var idIndex = xmlForId.indexOf('resource-id="');
  370.     while (idIndex !== -1) {
  371.         var endIndex = xmlForId.indexOf('"', idIndex + 13);
  372.         if (endIndex !== -1) {
  373.             var id = xmlForId.substring(idIndex + 13, endIndex);
  374.             if (id && !id.match(/^com\.android/) && !所有Ids[id]) {
  375.                 所有Ids.push(id);
  376.                 所有Ids[id] = true;
  377.             }
  378.         }
  379.         idIndex = xmlForId.indexOf('resource-id="', idIndex + 13);
  380.     }
  381.     print.log("⚠ 未找到指定 resourceId,当前界面可用 resource-id 列表(前10个):");
  382.     for (var i = 0; i < Math.min(10, 所有Ids.length); i++) {
  383.         print.log("  - " + 所有Ids[i]);
  384.     }
  385. }

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

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

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

  396.         var 后面 = xml.substring(索引);
  397.         var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  398.         if (m) {
  399.             var left = parseInt(m[1]);
  400.             var top = parseInt(m[2]);
  401.             var right = parseInt(m[3]);
  402.             var bottom = parseInt(m[4]);
  403.             结果.push({
  404.                 left: left,
  405.                 top: top,
  406.                 right: right,
  407.                 bottom: bottom,
  408.                 centerX: (left + right) / 2,
  409.                 centerY: (top + bottom) / 2,
  410.                 width: right - left,
  411.                 height: bottom - top
  412.             });
  413.         }
  414.         位置 = 索引 + 查找值.length;
  415.     }
  416.     return 结果;
  417. }

  418. var xmlForClass = 获取UI();

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

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

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

  432. function 通过ContentDesc查找节点(xml, desc) {
  433.     var 索引 = xml.indexOf('content-desc="' + desc + '"');
  434.     if (索引 === -1) {
  435.         return null;
  436.     }
  437.     var 后面 = xml.substring(索引);
  438.     var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  439.     if (!m) {
  440.         return null;
  441.     }
  442.     var left = parseInt(m[1]);
  443.     var top = parseInt(m[2]);
  444.     var right = parseInt(m[3]);
  445.     var bottom = parseInt(m[4]);
  446.     return {
  447.         left: left,
  448.         top: top,
  449.         right: right,
  450.         bottom: bottom,
  451.         centerX: (left + right) / 2,
  452.         centerY: (top + bottom) / 2
  453.     };
  454. }

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

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

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

  466. function 通过Hint查找输入框(xml, hint) {
  467.     var 索引 = xml.indexOf('hint="' + hint + '"');
  468.     if (索引 === -1) {
  469.         // 尝试变体
  470.         var 变体 = [hint, "请输入" + hint, "输入" + hint, "写" + hint];
  471.         for (var i = 0; i < 变体.length; i++) {
  472.             索引 = xml.indexOf('hint="' + 变体[i] + '"');
  473.             if (索引 !== -1) {
  474.                 hint = 变体[i];
  475.                 break;
  476.             }
  477.         }
  478.     }
  479.     if (索引 === -1) {
  480.         return null;
  481.     }
  482.     var 后面 = xml.substring(索引);
  483.     var m = 后面.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  484.     if (!m) {
  485.         return null;
  486.     }
  487.     return {
  488.         centerX: (parseInt(m[1]) + parseInt(m[3])) / 2,
  489.         centerY: (parseInt(m[2]) + parseInt(m[4])) / 2,
  490.         hint: hint
  491.     };
  492. }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  593.             if (m) {
  594.                 var left = parseInt(m[1]);
  595.                 var top = parseInt(m[2]);
  596.                 var right = parseInt(m[3]);
  597.                 var bottom = parseInt(m[4]);
  598.                 var cx = (left + right) / 2;
  599.                 var cy = (top + bottom) / 2;

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

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

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

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

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

  628. function 带重试的操作(操作函数, 操作名, 最大重试) {
  629.     最大重试 = 最大重试 || 3;
  630.     for (var i = 1; i <= 最大重试; i++) {
  631.         try {
  632.             print.log("第 " + i + "/" + 最大重试 + " 次尝试 " + 操作名);
  633.             var 结果 = 操作函数();
  634.             if (结果) {
  635.                 print.log("✓ " + 操作名 + " 成功");
  636.                 return true;
  637.             }
  638.         } catch (e) {
  639.             print.log("⚠ 第 " + i + " 次出错:" + e.message);
  640.         }
  641.         if (i < 最大重试) {
  642.             sleep.second(秒 = 1);
  643.         }
  644.     }
  645.     print.log("✗ " + 操作名 + " 失败,已重试 " + 最大重试 + " 次");
  646.     return false;
  647. }

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

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

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

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

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

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

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

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

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

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

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

  683. print.log("\n===== 示例结束 =====");
复制代码



unto完整苹果IOS小脚本文本输入与粘贴流程nextnocontent
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关导读了
    采集亚马逊正版群发工具有没有?
    Apr.20旅行X心语今天来说说YYPOST新功能的一个灵活用法,采集亚马逊商品信息,并且获得排名的软件,亚马逊现在越来越多客户做,淘宝的水是越来越清了,以前做电商的客户,现在都转战到外国,最赚钱的要数一些客户往亚马逊里堆了吧,拿我这个YYPOST的客户,最多的是采集,分析排名,刷价格,刷数量,改价,刷访问量等等技术

    企业发展B2B网站有什么东东软件可以发呢
    标题企业发展网B2B软件,现在虽然B2B网站收录不错,可愁的是心急的人们,他们太想一口吃撑胖子了,发帖宣传虽然不能像佛系那样淡定,但也不能像跑火车那般急躁对待,自己内容不收录,完全是自己操作内容问题,可以参考一下别人的内容是怎么弄的,然后自己要试着转变,而且收录这个内容,常常会变化的,不是一种规则就吃到老

    搜房天下房聊软件哪一个好呢
    本帖最后由 发帖软件 于 2019-5-22 16:15 编辑 2搜房天下群发房聊信息软件,开始本来打算做58同城的,但发一个就要一次点触验证码,这就让人没有感觉到存在的价值了吧,都是卖二手房和新房的搜房天下倒是可以发即时聊天信息,也没有发现他这个网站有啥子限制,登陆一个搜房天下账号,然后采集回来分类列表的网址,然后就一

    大家坛有没有好用的群发工具下载呢
    当你的笑容给我礼貌的招呼,大家坛全自动发帖软件,宣传推广是一场持久战,总是有一些人把软件用了一天,或是几个小时,就觉得自己付出太多了,那加进来的粉丝,或是流量,应该是和宣传多少成正比的,其实没有这么便宜的事,就像很多阅读量超过一百万的视频,或是电影,真正会在屏幕打赏的人不会超过三千,真正大额打赏给主

    群发正版软件中国塑料网
    中国塑料网群发软件YYPOST脚本下载地址,这个网站会有一个很奇怪的问题就是你在首页登陆无半个验证码,但在登陆网址登陆就会有一个验证码,所以我们灵活一些,在首页登陆就不用输入验证码了哈。网站秒收录比较高,但发的都是五金和建筑行业,先前有很多人都是发土建工程的大公司操作的,现在这个网站专为那个行业诞生的吧。

    OpenStreetMap网站正版2019年发帖工具下载
    本帖最后由 发帖软件 于 2019-5-21 11:13 编辑 OpenStreetMap网站全自动群发,OpenStreetMapOpenStreetMap(简称OSM,中文是公开地图)是一个网上地图协作计划,目标是创造一个内容自由且能让所有人编辑的世界地图。有的人编辑地图然后等收录,有的人发日志等收录,我们这里也是利用地图日志做为宣传的目标,简单的脚本理

    搜房天下全自动收短信全自动识别验证码注册账号软件
    房天下自动注册机,这个脚本是前几天发房聊的脚本廷伸品种,这个脚本能做到自动注册账号,自动保存账号,自动发房聊的效果,不过今天我们主要说一说怎么注册账号写脚本吧,这个搜房天天下的账号,可以发提问,可以发房聊,发论坛,发博客,还有发个人中心页都是有秒收的效果的,这样就省去了去买号,去乱花钱的效果了吧,而

    企业邮箱安卓端有什么APP软件可以发的呢
    请输入标题企业邮箱安卓发发送邮箱脚本,这个脚本是利用企业邮箱进行群发的,全程是一种模拟手工操作的过程,所以封号是很少的,而且企业邮箱群发到普通QQ邮箱不容易进垃圾箱中的,所以这个脚本也是这样的原理,不过最好是利用一些多开器,登陆多点的QQ邮箱账号会比较流畅一些,然后用软件一个一个的切换APP进行群发邮件会

    头条留评论软件有没有好用的呢?
    今天整一个今日头条留言软件,对于留言YYPOST是优势是比较大的存在,因为他往往专注一些下拉定位的优点,像今日头条这样,还是需要一些特殊下拉定位的,因为他新闻有长有短,有图有视频的,所以综合起来定位是比较难的,如果用POST也不是很轻松可以破解他的加密参数。这个脚本也是有一个不好的地方就是换号会比较麻烦,您电

    单网页生成神器
    最近新技术,网页生成机占领了整个网络的半壁江山,效果很疯狂,虽然不知道能持续多久,作为开发软件的领头者,一直在找收录的方法,一直在努力创新着,一直被人模仿,却从没有被超越过,这个网页生成机,已经出来有一段时间了,一直没有拿出来分享,醉过醉过,它是利用的一些小小收录漏洞整的,您最好用一些老站域名,进行

关闭
快速回复 返回列表 返回顶部
本站自动发贴软件,是现在最流行的做脚本软件,这种发贴工具,不但发贴收录快,而且抢占好的先机,完全自由编辑,实现针对性群发模拟操作,软件可以顶贴,也可以发贴,可以兼容支持Discuz、PHPWind、Dvbbs三大主流论坛,有手机验证码收件,邮件收发的功能,支持验证码识别,注册问题识别,多线程任务,自动上传头像,自动激活注册邮件,兼容防注册插件,本站软件原创正版,更新效率最快的原创软件。 『网络推广软件』『自动发帖软件』『 自动发帖