信息发布软件,b2b软件,广告发布软件

 找回密码
 立即注册
搜索
查看: 2|回复: 0
打印 上一主题 下一主题

[宣传软件网站动态] AIWROK手机指挥台停止与开始执行器

[复制链接]

1968

主题

1978

帖子

1万

积分

积分
11536

资讯缩略图:

资讯发布日期:2026-09-03

资讯发布简介:AIWROK手机指挥台停止与开始执行器

资讯关键词:AIWROK手机指挥台停止与开始执行器

资讯所属分类:IT资讯 

联系:

① 本信息收集于网络,如有不对的地方欢迎联系我纠正!
② 本信息免费收录,不存在价格的问题!
③ 如果您的网站也想这样出现在这里,请您加好友情链接,我当天会审核通过!

④友情链接关键字:软件网站分类目录 网址:http://www.postbbs.com/

资讯详细描述
AIWROK手机指挥台停止与开始执行器
AIWROK手机指挥台停止与开始执行器 b2b软件
AIWROK手机指挥台停止与开始执行器 b2b软件
AIWROK手机指挥台停止与开始执行器 b2b软件
AIWROK手机指挥台停止与开始执行器 b2b软件

https://www.yuque.com/aiwork/nba2pr/ssiowosqrnpscnef
  1. /**
  2. * AIWROK 手机执行器(MQTT 群控端 · 增强版)
  3. * ------------------------------------------------------------------
  4. * 配套:指挥台.html(电脑浏览器打开)
  5. *
  6. * 主题约定(ROOM 换成你自己的房间号,避免和别人串台)
  7. *   收:aiwrok/<ROOM>/cmd/<本机机号>     只发给某一台
  8. *   收:aiwrok/<ROOM>/cmd/all            广播,所有机器都执行
  9. *   发:aiwrok/<ROOM>/ret/<本机机号>     心跳 + 执行结果 + 截图
  10. *
  11. * 指令清单(JSON,带 "id" 的回执会原样带回,电脑端用来算耗时)
  12. *   {"cmd":"PING"}                                   测连通
  13. *   {"cmd":"INFO"}                                   完整环境快照
  14. *   {"cmd":"STATUS"}                                 运行状态
  15. *   {"cmd":"SHOT","w":540,"q":60}                    截图回传(可临时改缩放/质量)
  16. *   {"cmd":"CLICK","x":540,"y":960}                  点坐标
  17. *   {"cmd":"SWIPE","x1":540,"y1":1400,"x2":540,"y2":500,"ms":300}   滑动
  18. *   {"cmd":"TEXT","text":"你好"}                      输入(sendString)
  19. *   {"cmd":"CLIP","text":"你好"}                      输入(剪贴板+长按粘贴)
  20. *   {"cmd":"FIND","text":"点赞","tap":1}              按屏幕文字找,找到就点
  21. *   {"cmd":"APP","pkg":"com.tencent.mm"}             打开应用
  22. *   {"cmd":"HOME"} / {"cmd":"BACK"}
  23. *   {"cmd":"WAIT","ms":3000}                         等待
  24. *   {"cmd":"LOOP","act":"SWIPE","count":30,"min":2000,"max":2000}   循环
  25. *   {"cmd":"STOP"}                                   停循环
  26. *   {"cmd":"RAND","on":1,"px":20}                    随机偏移开关(防风控)
  27. *   {"cmd":"TASK","steps":[{"cmd":"APP","pkg":"..."},{"cmd":"WAIT","ms":4000},{"cmd":"SWIPE"},{"cmd":"FIND","text":"点赞"}]}
  28. *                                                    任务编排:按顺序跑一整套
  29. *   {"cmd":"SELFTEST"}                               一键自检:逐项体检报 pass/fail
  30. * ------------------------------------------------------------------
  31. * 日志:每条指令都打 序号/来源/参数/耗时/结果/回传字节,循环和任务每步都打,
  32. *       绝不静默执行。
  33. * ------------------------------------------------------------------
  34. */

  35. // ==================== 配置:只改这三行 ====================
  36. var ROOM      = "room001";                 // 房间号,多台电脑/多套设备用它隔离
  37. var DEV_ID    = "";                        // 机号,留空=自动用 IMEI 后 6 位
  38. var BROKER    = "tcp://broker.emqx.io:1883";
  39. var SHOT_MAXW = 540;      // 回传截图最大宽度,超出等比缩小
  40. var SHOT_QUAL = 60;       // JPEG 质量 1-100,调小更省流量更不易掉线
  41. var VER       = "v6";     // 版本号,日志里能看到跑的是哪版
  42. // ========================================================

  43. var T = { cmdMine: "", cmdAll: "", ret: "" };

  44. // ---------- 日志 ----------
  45. // 重要:printl 只能在脚本主线程调用。Paho 的回调(收消息/掉线)跑在别的
  46. // Java 线程上,在那里直接 printl 会抛异常并打死消息派发线程,表现为
  47. // "只收到第一条指令,之后全部丢失,最后 32000 超时掉线"。
  48. var IN_CALLBACK = false;
  49. var LOGQ = [];

  50. function log(s) {
  51.     if (IN_CALLBACK) {
  52.         if (LOGQ.length < 800) LOGQ.push(s);   // 回调线程:只入队,绝不 printl
  53.     } else {
  54.         try { printl("[执行器] " + s); } catch (e) {}
  55.     }
  56. }
  57. function logk(s) { log(s); }                   // 关键节点,写法统一方便过滤

  58. function flushLog() {
  59.     var n = 0;
  60.     while (LOGQ.length > 0 && n < 40) {
  61.         try { printl("[执行器] " + LOGQ.shift()); } catch (e) { LOGQ.length = 0; break; }
  62.         n++;
  63.     }
  64. }

  65. // ==================== 1. 加载 Paho ====================
  66. try {
  67.     rhino.loadDex("paho-mqtt.dex");
  68.     log("[1/6] dex 已加载 paho-mqtt.dex");
  69. } catch (e) {
  70.     log("[1/6] loadDex 跳过(可能系统已自动加载插件):" + e.message);
  71. }

  72. try {
  73.     importClass(Packages.org.eclipse.paho.client.mqttv3.MqttClient);
  74.     importClass(Packages.org.eclipse.paho.client.mqttv3.MqttConnectOptions);
  75.     importClass(Packages.org.eclipse.paho.client.mqttv3.MqttCallback);
  76.     importClass(Packages.org.eclipse.paho.client.mqttv3.MqttMessage);
  77.     importClass(Packages.org.eclipse.paho.client.mqttv3.persist.MemoryPersistence);
  78.     log("[2/6] Paho 类导入成功");
  79. } catch (e) {
  80.     log("[2/6] Paho 类导入失败:" + e.message);
  81.     log("      请把 paho-mqtt.dex 放到本工程的 插件\\ 目录后重跑");
  82.     exit();
  83. }

  84. // ==================== 2. 设备信息 ====================
  85. function deviceInfo() {
  86.     var o = { brand: "?", model: "?", imei: "", w: 0, h: 0, android: "?", sdk: "?" };
  87.     try { o.brand = "" + device.getBrand(); } catch (e) {}
  88.     try { o.model = "" + device.getModel(); }  catch (e) {}
  89.     try { o.imei  = "" + device.getIMEI(); }   catch (e) {}
  90.     try { o.w = screen.getScreenWidth(); o.h = screen.getScreenHeight(); } catch (e) {}
  91.     try { o.android = "" + java.lang.System.getProperty("os.version"); } catch (e) {}
  92.     try { o.sdk = "" + Packages.android.os.Build.VERSION.SDK_INT; } catch (e) {}
  93.     return o;
  94. }
  95. var INFO = deviceInfo();
  96. if (!DEV_ID) {
  97.     DEV_ID = INFO.imei ? ("" + INFO.imei).slice(-6) : ("dev" + Math.floor(Math.random() * 10000));
  98. }
  99. DEV_ID = "" + DEV_ID;
  100. T.cmdMine = "aiwrok/" + ROOM + "/cmd/" + DEV_ID;
  101. T.cmdAll  = "aiwrok/" + ROOM + "/cmd/all";
  102. T.ret     = "aiwrok/" + ROOM + "/ret/" + DEV_ID;

  103. // ==================== 3. 状态 ====================
  104. var client = null, connected = false;
  105. var startAt = (new Date()).getTime();
  106. var nRecv = 0, nSent = 0, nRun = 0, nErr = 0;
  107. var loopOn = false, loopTotal = 0, loopTimes = 0;
  108. var taskOn = false, taskStep = 0, taskTotal = 0;
  109. var CMDQ = [];                              // 回调线程入队,主线程执行
  110. var randOn = 0, randPx = 20;                // 随机偏移(防风控)

  111. // ==================== 4. 回传 ====================
  112. function report(obj, retain) {
  113.     if (!connected) { log("回传丢弃(未连接) type=" + obj.type); return; }
  114.     try {
  115.         obj.dev = DEV_ID; obj.room = ROOM; obj.ver = VER;
  116.         obj.brand = INFO.brand; obj.model = INFO.model;
  117.         obj.screen = INFO.w + "x" + INFO.h;
  118.         obj.ts = (new Date()).getTime();
  119.         var body = JSON.stringify(obj);
  120.         var m = new MqttMessage();
  121.         m.setPayload(new java.lang.String(body).getBytes("UTF-8"));
  122.         m.setQos(retain ? 1 : 0);
  123.         if (retain) m.setRetained(true);
  124.         client.publish(T.ret, m);
  125.         nSent++;
  126.         log("→ 回传 " + T.ret + " type=" + obj.type +
  127.             (obj.cmd ? ("/" + obj.cmd) : "") + " 字节=" + body.length);
  128.     } catch (e) { nErr++; log("回传失败:" + e.message); }
  129. }

  130. // ==================== 5. 基础动作 ====================
  131. function jitter(v) {
  132.     if (!randOn) return v;
  133.     var d = Math.floor(Math.random() * (randPx * 2 + 1)) - randPx;
  134.     var r = v + d;
  135.     if (r < 1) r = 1;
  136.     return r;
  137. }
  138. function doClick(x, y) {
  139.     var jx = jitter(x), jy = jitter(y);
  140.     auto.clickPoint(jx, jy);
  141.     return { x: jx, y: jy, raw: x + "," + y, rand: randOn ? 1 : 0 };
  142. }
  143. function doSwipe(o) {
  144.     var x1 = jitter(o.x1 || Math.floor(INFO.w / 2)),     y1 = jitter(o.y1 || Math.floor(INFO.h * 0.75));
  145.     var x2 = jitter(o.x2 || Math.floor(INFO.w / 2)),     y2 = jitter(o.y2 || Math.floor(INFO.h * 0.25));
  146.     var ms = o.ms || 300;
  147.     auto.swip(x1, y1, x2, y2, ms, 0);
  148.     return { x1: x1, y1: y1, x2: x2, y2: y2, ms: ms, rand: randOn ? 1 : 0 };
  149. }
  150. function doText(t) {
  151.     input.sendString(t);
  152.     return { len: ("" + t).length, way: "sendString" };
  153. }
  154. // 剪贴板输入:sendString 不生效时用它(需输入框已聚焦,再长按选"粘贴")
  155. function doClip(t) {
  156.     var s = "" + t;
  157.     try {
  158.         if (typeof Clipboard !== "undefined" && Clipboard && typeof Clipboard.copy === "function") {
  159.             Clipboard.copy(s);
  160.             return { len: s.length, way: "Clipboard.copy" };
  161.         }
  162.     } catch (e1) { throw new Error("Clipboard.copy 失败:" + e1.message); }
  163.     try {
  164.         if (typeof clipboard !== "undefined" && clipboard && typeof clipboard.copy === "function") {
  165.             clipboard.copy(s);
  166.             return { len: s.length, way: "clipboard.copy" };
  167.         }
  168.     } catch (e2) { throw new Error("clipboard.copy 失败:" + e2.message); }
  169.     throw new Error("本机无剪贴板接口(Clipboard/clipboard 都不可用),请改用 TEXT");
  170. }
  171. function doShot(maxW, qual) {
  172.     var mw = maxW || SHOT_MAXW, qq = qual || SHOT_QUAL;
  173.     var bmp = screen.screenShotFull();
  174.     if (!bmp) throw new Error("截图返回空");
  175.     var b64 = null;
  176.     try {
  177.         var w = bmp.getWidth(), h = bmp.getHeight();
  178.         var target = bmp, from = null;
  179.         try {
  180.             if (w > mw) {
  181.                 var sc = mw / w;
  182.                 var mx = new Packages.android.graphics.Matrix();
  183.                 mx.postScale(sc, sc);
  184.                 target = Packages.android.graphics.Bitmap.createBitmap(bmp, 0, 0, w, h, mx, true);
  185.                 from = target;
  186.             }
  187.         } catch (eScale) { target = bmp; }
  188.         var bos = new java.io.ByteArrayOutputStream();
  189.         target.compress(Packages.android.graphics.Bitmap.CompressFormat.JPEG, qq, bos);
  190.         b64 = "" + Packages.android.util.Base64.encodeToString(bos.toByteArray(),
  191.                 Packages.android.util.Base64.NO_WRAP);
  192.         if (from) { try { from.recycle(); } catch (e2) {} }
  193.     } catch (e) {
  194.         try { b64 = "" + bmp.toBase64(); } catch (e5) { b64 = null; }
  195.     }
  196.     if (!b64 || b64.length < 32) {
  197.         try { bmp.recycle(); } catch (e3) {}
  198.         throw new Error("截图编码失败");
  199.     }
  200.     try { bmp.recycle(); } catch (e4) {}
  201.     var kb = Math.round(b64.length / 1024);
  202.     if (kb > 400) throw new Error("截图仍过大 " + kb + "KB,调小 w 或 q");
  203.     return { img: b64, kb: kb };
  204. }
  205. function doApp(pkg) {
  206.     if (!pkg) throw new Error("缺少 pkg 包名");
  207.     app.openApp(pkg);
  208.     return { pkg: pkg };
  209. }
  210. function doHome() { auto.home(); return {}; }
  211. function doBack() {
  212.     if (typeof auto.back === "function") { auto.back(); return {}; }
  213.     throw new Error("此版本 auto 无 back(),改用 CLICK 点返回键坐标");
  214. }
  215. // 按屏幕文字查找,找到就点中心(依赖 UI 树,部分应用读不到会报未找到)
  216. function doFind(text, tap) {
  217.     var xml = "";
  218.     try { xml = "" + agent.getXml(); }
  219.     catch (e) { throw new Error("读取界面失败:" + e.message); }
  220.     if (!xml || xml.length < 20) throw new Error("界面内容为空");
  221.     var idx = xml.indexOf('text="' + text + '"');
  222.     if (idx < 0) { return { found: 0, text: text }; }
  223.     var seg = xml.substring(idx, idx + 600);
  224.     var bm = seg.match(/bounds="\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]"/);
  225.     if (!bm) return { found: 1, tapped: 0, text: text, note: "找到但无坐标" };
  226.     var cx = Math.round(parseInt(bm[1], 10) + (parseInt(bm[3], 10) - parseInt(bm[1], 10)) / 2);
  227.     var cy = Math.round(parseInt(bm[2], 10) + (parseInt(bm[4], 10) - parseInt(bm[2], 10)) / 2);
  228.     var out = { found: 1, text: text, x: cx, y: cy, bounds: bm[0] };
  229.     if (tap === undefined || tap) { auto.clickPoint(cx, cy); out.tapped = 1; }
  230.     return out;
  231. }

  232. // ==================== 6. 统一执行入口(handle / TASK / SELFTEST 都走这里) ==========
  233. function execCmd(o) {
  234.     var cmd = (o.cmd || "").toUpperCase();
  235.     var res = { cmd: cmd, ok: false };
  236.     var t0 = (new Date()).getTime();

  237.     if (cmd === "PING")       { res.ok = true; res.msg = "pong"; }
  238.     else if (cmd === "INFO")  {
  239.         res.ok = true;
  240.         res.env = { brand: INFO.brand, model: INFO.model, imei: INFO.imei,
  241.                     screen: INFO.w + "x" + INFO.h, android: INFO.android, sdk: INFO.sdk,
  242.                     room: ROOM, dev: DEV_ID, ver: VER, broker: BROKER,
  243.                     sub: [T.cmdMine, T.cmdAll], pub: T.ret,
  244.                     shot: { maxW: SHOT_MAXW, qual: SHOT_QUAL }, rand: { on: randOn, px: randPx } };
  245.     }
  246.     else if (cmd === "STATUS"){
  247.         res.ok = true;
  248.         res.info = { up: Math.round(((new Date()).getTime() - startAt) / 1000),
  249.                      recv: nRecv, sent: nSent, run: nRun, err: nErr,
  250.                      loop: loopOn, loopTimes: loopTimes, loopTotal: loopTotal,
  251.                      task: taskOn, taskStep: taskStep, taskTotal: taskTotal,
  252.                      rand: randOn, connected: connected };
  253.     }
  254.     else if (cmd === "CLICK") { var px = parseInt(o.x, 10), py = parseInt(o.y, 10);
  255.                                 if (isNaN(px) || isNaN(py)) throw new Error("坐标无效 x=" + o.x + " y=" + o.y);
  256.                                 res.ok = true; res.data = doClick(px, py); }
  257.     else if (cmd === "SWIPE") { res.ok = true; res.data = doSwipe(o); }
  258.     else if (cmd === "TEXT")  { if (!o.text) throw new Error("缺少 text");
  259.                                 res.ok = true; res.data = doText(o.text); }
  260.     else if (cmd === "CLIP")  { if (!o.text) throw new Error("缺少 text");
  261.                                 res.ok = true; res.data = doClip(o.text); }
  262.     else if (cmd === "FIND")  { if (!o.text) throw new Error("缺少 text");
  263.                                 res.ok = true; res.data = doFind(o.text, o.tap); }
  264.     else if (cmd === "SHOT")  { var r = doShot(o.w, o.q);
  265.                                 res.ok = true; res.kb = r.kb; res.img = r.img; }
  266.     else if (cmd === "APP")   { res.ok = true; res.data = doApp(o.pkg); }
  267.     else if (cmd === "HOME")  { res.ok = true; doHome(); res.msg = "已回桌面"; }
  268.     else if (cmd === "BACK")  { res.ok = true; doBack(); res.msg = "已返回"; }
  269.     else if (cmd === "WAIT")  { res.ok = true; res.wait = o.ms || 1000; }
  270.     else if (cmd === "RAND")  { randOn = o.on ? 1 : 0; randPx = o.px || randPx;
  271.                                 res.ok = true; res.msg = "随机偏移=" + (randOn ? ("开 " + randPx + "px") : "关"); }
  272.     else if (cmd === "STOP")  { loopOn = false; taskOn = false;
  273.                                 res.ok = true; res.msg = "已发停止(循环+任务)"; }
  274.     else { throw new Error("未知指令 " + cmd); }

  275.     res.ms = (new Date()).getTime() - t0;
  276.     return res;
  277. }

  278. // ==================== 7. 任务编排:按顺序跑一组步骤 ====================
  279. function runTask(steps) {
  280.     if (!steps || !steps.length) throw new Error("steps 为空");
  281.     taskOn = true; taskStep = 0; taskTotal = steps.length;
  282.     logk("任务开始 共 " + steps.length + " 步:" + JSON.stringify(steps).slice(0, 200));
  283.     report({ type: "TASK", state: "start", total: steps.length });

  284.     (function next(i) {
  285.         if (!taskOn) {
  286.             logk("任务已停止,完成 " + i + "/" + steps.length + " 步");
  287.             report({ type: "TASK", state: "stop", step: i, total: steps.length });
  288.             return;
  289.         }
  290.         if (i >= steps.length) {
  291.             taskOn = false;
  292.             logk("任务全部完成,共 " + steps.length + " 步");
  293.             report({ type: "TASK", state: "done", step: steps.length, total: steps.length });
  294.             return;
  295.         }
  296.         var s = steps[i] || {};
  297.         taskStep = i + 1;
  298.         var one = { type: "TASK", state: "run", step: i + 1, total: steps.length, cmd: (s.cmd || "").toUpperCase() };
  299.         try {
  300.             var r = execCmd(s);
  301.             one.ok = r.ok; one.ms = r.ms;
  302.             if (r.data) one.data = r.data;
  303.             if (r.img) { report({ type: "SHOT", ok: true, kb: r.kb, img: r.img, step: i + 1 }); one.kb = r.kb; }
  304.             log("任务 第" + (i + 1) + "/" + steps.length + "步 " + one.cmd + " 成功 耗时=" + r.ms + "ms" +
  305.                 (r.data ? (" 参数=" + JSON.stringify(r.data)) : ""));
  306.         } catch (e) {
  307.             nErr++;
  308.             one.ok = false; one.err = "" + e.message;
  309.             log("任务 第" + (i + 1) + "/" + steps.length + "步 " + one.cmd + " 失败:" + e.message);
  310.         }
  311.         report(one);
  312.         nRun++;
  313.         var wait = (one.cmd === "WAIT") ? (s.ms || 1000) : 300;
  314.         setTimeout(function () { next(i + 1); }, wait);
  315.     })(0);
  316. }

  317. // ==================== 8. 一键自检:逐项体检 ====================
  318. function runSelfTest() {
  319.     logk("自检开始(7 项)");
  320.     report({ type: "SELFTEST", state: "start" });
  321.     var items = [];
  322.     var plan = [
  323.         { name: "屏幕分辨率", run: function () {
  324.             if (!INFO.w || !INFO.h) throw new Error("读不到宽高");
  325.             return INFO.w + "x" + INFO.h; } },
  326.         { name: "截图能力", run: function () {
  327.             var r = doShot(320, 50); return r.kb + "KB"; } },
  328.         { name: "点击能力", run: function () {
  329.             doClick(Math.floor(INFO.w / 2), Math.floor(INFO.h / 2)); return "已点中心"; } },
  330.         { name: "滑动能力", run: function () {
  331.             doSwipe({}); return "已上滑一次"; } },
  332.         { name: "UI树读取", run: function () {
  333.             var x = "" + agent.getXml();
  334.             if (!x || x.length < 20) throw new Error("UI树为空");
  335.             return x.length + " 字节"; } },
  336.         { name: "MQTT回传", run: function () {
  337.             if (!connected) throw new Error("未连接"); return "在线"; } },
  338.         { name: "随机偏移", run: function () {
  339.             return randOn ? ("开 " + randPx + "px") : "关"; } }
  340.     ];
  341.     (function one(i) {
  342.         if (i >= plan.length) {
  343.             var pass = 0;
  344.             for (var k = 0; k < items.length; k++) { if (items[k].ok) pass++; }
  345.             logk("自检完成 通过 " + pass + "/" + plan.length);
  346.             report({ type: "SELFTEST", state: "done", pass: pass, total: plan.length, items: items });
  347.             return;
  348.         }
  349.         var p = plan[i];
  350.         var it = { name: p.name, ok: false };
  351.         try { it.msg = p.run(); it.ok = true; log("自检 [" + (i + 1) + "/" + plan.length + "] " + p.name + " 通过:" + it.msg); }
  352.         catch (e) { it.msg = "" + e.message; log("自检 [" + (i + 1) + "/" + plan.length + "] " + p.name + " 失败:" + it.msg); }
  353.         items.push(it);
  354.         report({ type: "SELFTEST", state: "run", item: p.name, ok: it.ok, msg: it.msg, step: i + 1, total: plan.length });
  355.         setTimeout(function () { one(i + 1); }, 400);
  356.     })(0);
  357. }

  358. // ==================== 9. 循环养机 ====================
  359. function runLoop(o) {
  360.     loopOn = true;
  361.     var act = o.act || "SWIPE";
  362.     var count = o.count || 0;
  363.     var minMs = o.min || 2000, maxMs = o.max || 2000;
  364.     var i = 0;
  365.     loopTotal = count; loopTimes = 0;
  366.     logk("循环开始 动作=" + act + " 次数=" + (count > 0 ? count : "无限") + " 间隔=" + minMs + "~" + maxMs + "ms");
  367.     report({ type: "LOOP", state: "start", act: act, count: count, times: 0 });

  368.     (function step() {
  369.         if (!loopOn) {
  370.             logk("循环已停止,实际执行 " + i + " 次");
  371.             report({ type: "LOOP", state: "stop", times: i });
  372.             return;
  373.         }
  374.         try {
  375.             var r = execCmd({ cmd: act, x1: o.x1, y1: o.y1, x2: o.x2, y2: o.y2, ms: o.ms, x: o.x, y: o.y, text: o.text, pkg: o.pkg });
  376.             nRun++; i++; loopTimes = i;
  377.             log("循环 第" + i + "次/" + (count > 0 ? count : "∞") + " " + act + " 成功 耗时=" + r.ms + "ms" +
  378.                 (r.data ? (" " + JSON.stringify(r.data)) : ""));
  379.             if (r.img) report({ type: "SHOT", ok: true, kb: r.kb, img: r.img });
  380.             report({ type: "LOOP", state: "run", act: act, times: i, total: count, ms: r.ms });
  381.         } catch (e) {
  382.             nErr++;
  383.             log("循环 第" + (i + 1) + "次 失败:" + e.message);
  384.             report({ type: "LOOP", state: "err", err: e.message, times: i });
  385.         }
  386.         if (count > 0 && i >= count) {
  387.             loopOn = false;
  388.             logk("循环完成,共 " + i + " 次");
  389.             report({ type: "LOOP", state: "done", times: i });
  390.             return;
  391.         }
  392.         var wait = minMs + Math.floor(Math.random() * Math.max(1, maxMs - minMs));
  393.         log("下一次将在 " + wait + "ms 后(发 STOP 可停)");
  394.         setTimeout(step, wait);
  395.     })();
  396. }

  397. // ==================== 10. 指令分发 ====================
  398. function handle(raw, from) {
  399.     nRecv++;
  400.     var o;
  401.     try { o = JSON.parse(raw); }
  402.     catch (e) { nErr++; log("收到非 JSON,忽略:" + raw.slice(0, 120)); return; }

  403.     var cmd = (o.cmd || "").toUpperCase();
  404.     log("收到 #" + nRecv + " " + cmd + " 来源=" + from + " id=" + (o.id || "-") +
  405.         " 参数=" + raw.slice(0, 200));

  406.     // 三个特殊指令单独走(异步链式执行)
  407.     if (cmd === "LOOP") { runLoop(o); report({ type: "ACK", cmd: cmd, id: o.id || "", ok: true, msg: "循环已启动" }); return; }
  408.     if (cmd === "TASK") {
  409.         try { runTask(o.steps); report({ type: "ACK", cmd: cmd, id: o.id || "", ok: true, msg: "任务已启动 共" + o.steps.length + "步" }); }
  410.         catch (e) { nErr++; report({ type: "ACK", cmd: cmd, id: o.id || "", ok: false, err: e.message }); }
  411.         return;
  412.     }
  413.     if (cmd === "SELFTEST") {
  414.         runSelfTest();
  415.         report({ type: "ACK", cmd: cmd, id: o.id || "", ok: true, msg: "自检已启动" });
  416.         return;
  417.     }

  418.     var res = { type: "ACK", cmd: cmd, id: o.id || "" };
  419.     try {
  420.         var r = execCmd(o);
  421.         res.ok = r.ok; res.ms = r.ms;
  422.         if (r.msg) res.msg = r.msg;
  423.         if (r.data) res.data = r.data;
  424.         if (r.info) res.info = r.info;
  425.         if (r.env) res.env = r.env;
  426.         if (r.wait) res.wait = r.wait;
  427.         if (r.img) { res.kb = r.kb; res.img = r.img; }
  428.         log("执行 " + cmd + " 成功 耗时=" + r.ms + "ms");
  429.     } catch (e) {
  430.         nErr++;
  431.         res.ok = false; res.err = "" + e.message;
  432.         log("执行 " + cmd + " 失败:" + e.message);
  433.     }
  434.     report(res);
  435. }

  436. // ==================== 11. 连接 ====================
  437. function connect() {
  438.     var cid = "aiwrok_" + ROOM + "_" + DEV_ID + "_" + Math.floor(Math.random() * 10000);
  439.     logk("[3/6] 连接 " + BROKER + " clientId=" + cid);
  440.     client = new MqttClient(BROKER, cid, new MemoryPersistence());

  441.     var opt = new MqttConnectOptions();
  442.     opt.setCleanSession(true);
  443.     opt.setKeepAliveInterval(45);
  444.     opt.setConnectionTimeout(15);
  445.     opt.setAutomaticReconnect(true);

  446.     client.setCallback(new MqttCallback({
  447.         connectionLost: function (c) {
  448.             IN_CALLBACK = true;
  449.             try { connected = false; if (LOGQ.length < 800) LOGQ.push("掉线:" + c + "(看门狗将自动重连)"); }
  450.             finally { IN_CALLBACK = false; }
  451.         },
  452.         messageArrived: function (topic, msg) {
  453.             IN_CALLBACK = true;                       // 本线程禁止 printl / 禁止做重活
  454.             try {
  455.                 var text = "" + new java.lang.String(msg.getPayload(), "UTF-8");
  456.                 var from = ("" + topic === T.cmdAll) ? "广播" : "定向";
  457.                 if (CMDQ.length < 200) CMDQ.push({ raw: text, from: from });
  458.                 if (LOGQ.length < 800) LOGQ.push("收到原始包 主题=" + topic + " 字节=" + text.length);
  459.             } catch (e) {
  460.                 if (LOGQ.length < 800) LOGQ.push("收包异常:" + e.message);
  461.             } finally { IN_CALLBACK = false; }
  462.         },
  463.         deliveryComplete: function (t) { }
  464.     }));

  465.     client.connect(opt);
  466.     connected = true;
  467.     client.subscribe(T.cmdMine, 1);
  468.     client.subscribe(T.cmdAll, 1);
  469.     logk("[4/6] 已订阅 " + T.cmdMine);
  470.     logk("[4/6] 已订阅 " + T.cmdAll);
  471.     report({ type: "ONLINE" }, true);
  472.     flushLog();
  473. }

  474. // ==================== 12. 启动:打印完整环境 ====================
  475. logk("========== 执行器 " + VER + " 启动 ==========");
  476. log("设备品牌 = " + INFO.brand);
  477. log("设备型号 = " + INFO.model);
  478. log("IMEI     = " + (INFO.imei || "(无权限)"));
  479. log("安卓版本 = " + INFO.android + "  SDK=" + INFO.sdk);
  480. log("屏幕     = " + INFO.w + "x" + INFO.h);
  481. log("房间号   = " + ROOM + "   机号 = " + DEV_ID);
  482. log("Broker   = " + BROKER);
  483. log("订阅主题 = " + T.cmdMine + " , " + T.cmdAll);
  484. log("回传主题 = " + T.ret);
  485. log("截图参数 = 最大宽 " + SHOT_MAXW + "px, JPEG质量 " + SHOT_QUAL);
  486. log("支持指令 = PING INFO STATUS SHOT CLICK SWIPE TEXT CLIP FIND APP HOME BACK WAIT LOOP TASK SELFTEST STOP RAND");
  487. logk("[5/6] 环境读取完成");

  488. try { connect(); }
  489. catch (e) { connected = false; log("[6/6] 首次连接失败:" + e.message + ",看门狗持续重试"); }

  490. // ---------- 主线程看门狗:执行队列 + 刷日志 + 重连重订阅 ----------
  491. var tickSec = 0, retryAt = 0;
  492. setInterval(function () {
  493.     tickSec++;
  494.     // 1) 主线程执行排队指令(每轮最多 5 条)
  495.     var k = 0;
  496.     while (CMDQ.length > 0 && k < 5) {
  497.         var job = CMDQ.shift();
  498.         try { handle(job.raw, job.from); }
  499.         catch (e) { nErr++; log("指令执行异常:" + e.message); }
  500.         k++;
  501.     }
  502.     flushLog();                                        // 2) 刷回调日志
  503.     // 3) 连接状态同步
  504.     try {
  505.         var real = client ? client.isConnected() : false;
  506.         if (real && !connected) {
  507.             connected = true;
  508.             client.subscribe(T.cmdMine, 1);
  509.             client.subscribe(T.cmdAll, 1);
  510.             logk("已恢复连接并重新订阅(cleanSession 下必须重订阅)");
  511.             report({ type: "ONLINE" }, true);
  512.         }
  513.         if (!real && client && (tickSec - retryAt) >= 8) {
  514.             connected = false;
  515.             retryAt = tickSec;
  516.             log("第 " + tickSec + " 秒:未连接,主动触发重连…");
  517.             try { client.reconnect(); }
  518.             catch (e) {
  519.                 log("reconnect 失败:" + e.message + ",重建连接");
  520.                 try { connect(); } catch (e2) { log("重建失败:" + e2.message); }
  521.             }
  522.         }
  523.     } catch (e) { log("看门狗异常:" + e.message); }
  524. }, 1000);

  525. // ---------- 心跳 ----------
  526. var beat = 0;
  527. setInterval(function () {
  528.     beat++;
  529.     if (connected) {
  530.         report({ type: "HEART", up: beat * 20, recv: nRecv, sent: nSent, run: nRun,
  531.                  err: nErr, loop: loopOn, task: taskOn, rand: randOn });
  532.     } else {
  533.         log("心跳跳过(当前离线,看门狗重连中)");
  534.     }
  535. }, 20000);

  536. logk("[6/6] 已进入待命:每 1 秒取指令/查连接,每 20 秒心跳。停止请点 IDE 停止按钮");
复制代码






untoAIWROK手机执行器MQTT浏览器控端nextnocontent

QQ截图20260826146.png (933.97 KB, 下载次数: 0)

QQ截图20260826146.png
回复

使用道具 举报

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

本版积分规则

相关导读
群发软件AIWROK手机指挥台停止与开始执行器
AIWROK手机指挥台停止与开始执行器 https://www.yuque.com/aiwork/nba2pr/ssiowosqrnpscnef
群发软件AIWROK手机执行器MQTT浏览器控端
AIWROK手机执行器MQTT浏览器控端 https://www.yuque.com/aiwork/nba2pr/lalkm8cfnhswdrx8
群发软件MQTT协议示例AIWROK版
MQTT协议示例AIWROK版 https://www.yuque.com/aiwork/nba2pr/gw970kaylsvz7eyl
群发软件WSS协议示例 AIWROK 版websocket
WSS协议示例 AIWROK 版websocket
群发软件本地电脑部署YOLO找图服务器识别
本地电脑部署YOLO找图服务器识别 YOLO-Server.exe 下载服务器中转
群发软件AIWROK软件关闭/点赞场景 YOLOv5 检测示例
AIWROK软件关闭/点赞场景 YOLOv5 检测示例 https://www.yuque.com/aiwork/nba2pr/cx3tzty1qm0xeg7u
群发软件⛓️WebSocket带截图/点击/滑屏/按键/跑脚本/状态查询
⛓️WebSocket带截图/点击/滑屏/按键/跑脚本/状态查询
群发软件七猫阅读赚钱自动刷框架
七猫阅读赚钱自动刷框架
群发软件websocket远程停止手机接收器
websocket远程停止手机接收器
群发软件AIWROK软件本地搭建OCR找字服务器
AIWROK软件本地搭建OCR找字服务器
群发软件本地调试版原生websocket版
本地调试版原生websocket版
群发软件无障碍方式双指向中间滑动放大缩小完整示例
无障碍方式双指向中间滑动放大缩小完整示例
群发软件AIWROK双指向中间滑动捏合手势完整示例
AIWROK双指向中间滑动捏合手势完整示例
群发软件实战使用桌面控制WebSocket
实战使用桌面控制WebSocket
群发软件WebSocket调试okhttp版
WebSocket调试okhttp版
群发软件快手极速版自动刷视频
快手极速版自动刷视频
群发软件极速视频APP刷金币
极速视频APP刷金币
群发软件语音合成核心模块AIWROK 单文件版
语音合成核心模块AIWROK 单文件版
群发软件AIWROK软件自动文字转语音例子
AIWROK软件自动文字转语音例子
群发软件AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
群发软件安卓AIWROK获取包名所有方法汇总
安卓AIWROK获取包名所有方法汇总
群发软件AIWROK软件番茄小说自动阅读刷金币示例
AIWROK软件番茄小说自动阅读刷金币示例
信息发布软件AIWROK软件无碍模式一键删除所有APP版示例
AIWROK软件无碍模式一键删除所有APP版示例
信息发布软件AIWROK软件无碍模式auto模块抖音极速版滑动刷视频
AIWROK软件无碍模式auto模块抖音极速版滑动刷视频
信息发布软件快手极速版自动刷视频无障碍模式
快手极速版自动刷视频无障碍模式
信息发布软件AIWROK软件代理模式一键删除桌面所有APP版示例
AIWROK软件代理模式一键删除桌面所有APP版示例
信息发布软件AIWROK软件自动找图利用agent代理模式删除应用版示例
AIWROK软件自动找图利用agent代理模式删除应用版示例
信息发布软件解析Kimi返回的拖动距离示例
解析Kimi返回的拖动距离示例
信息发布软件自动截图并发送给DEEPSEEK识别示例过程
自动截图并发送给DEEPSEEK识别示例过程
信息发布软件AIWROK软件测试文心识别识别验证码示例
AIWROK软件测试文心识别识别验证码示例
信息发布软件元宝截图B站验证码示例测试
元宝截图B站验证码示例测试
信息发布软件示例千问自动采集文章保存记事本
示例千问自动采集文章保存记事本
信息发布软件豆包识别验证码加拖动验证码示例
豆包识别验证码加拖动验证码示例
信息发布软件豆包对话采集示例
豆包对话采集示例
信息发布软件启动自动百度贴吧发图片
启动自动百度贴吧发图片
信息发布软件自动百度贴吧示例
自动百度贴吧示例
信息发布软件代理模式简书自动流程
代理模式简书自动流程
信息发布软件启动极速版任务页看小说赚钱自动阅读
启动极速版任务页看小说赚钱自动阅读
信息发布软件agent代理模式功能小结
agent代理模式功能小结
信息发布软件完整苹果IOS小脚本文本输入与粘贴流程
完整苹果IOS小脚本文本输入与粘贴流程
信息发布软件AIWROK使用activity列表开关与进度条的协同交互
AIWROK使用activity列表开关与进度条的协同交互
群发软件苹果脚本找图后Detect对象各种方法演示
苹果脚本找图后Detect对象各种方法演示
群发软件苹果脚本网络API监控与数据管理工具
苹果脚本网络API监控与数据管理工具
群发软件IOS苹果脚本TXT文件读写H5日志打印完整示例
IOS苹果脚本TXT文件读写H5日志打印完整示例
群发软件AIWROK软件演示多线程创建暂停恢复
AIWROK软件演示多线程创建暂停恢复
群发软件AIWROK软件定时检查页面状态防止卡死技巧
AIWROK软件定时检查页面状态防止卡死技巧
群发软件安卓脚本runTime相关功能示例
安卓脚本runTime相关功能示例
群发软件floatUI实例秒显示秒关闭吐司功能
floatUI实例秒显示秒关闭吐司功能
群发软件苹果脚本HID多行实例粘帖板示例
苹果脚本HID多行实例粘帖板示例
群发软件安卓脚本HID节点查找完整方法示例
HID节点查找完整方法示例
群发软件AIWROK软件框架的抖音自动化营销系统
AIWROK软件框架的抖音自动化营销系统
群发软件赛博朋克任务控制中心H5示例
赛博朋克任务控制中心H5示例
群发软件苹果脚本现代深色UI设计风格
现代深色UI设计风格
群发软件AIWROK软件智能任务监控悬浮窗
AIWROK软件智能任务监控悬浮窗
群发软件AIWROK软件事件监听示例
AIWROK软件事件监听示例
群发软件QZ掘金原生UI界面
QZ掘金原生UI界面
群发软件安卓脚本auto方法完整示例
安卓脚本auto方法完整示例
群发软件安卓脚本暂停弹出确认对话框
安卓脚本暂停弹出确认对话框
群发软件苹果iOS脚本天气信息查询工具
苹果iOS脚本天气信息查询工具
群发软件安卓脚本简化版H5日志输出窗口
安卓脚本简化版H5日志输出窗口
群发软件安卓脚本简化版H5日志输出窗口
安卓脚本简化版H5日志输出窗口
群发软件安卓脚本应用重置、代理模式监控及补丁升级
安卓脚本应用重置、代理模式监控及补丁升级
群发软件安卓脚本里的打开关闭安装以及卡密授权信息
安卓脚本里的打开关闭安装以及卡密授权信息
群发软件AIWROK软件脚本GET下载文件并检测0KB工具
AIWROK软件脚本GET下载文件并检测0KB工具
群发软件安卓脚本HID按键方法完整示例
安卓脚本HID按键方法完整示例

QQ|( 京ICP备09078825号 )

本网站信息发布软件,是可以发布论坛,发送信息到各大博客,各大b2b软件自动发布,好不夸张的说:只要手工能发在电脑打开IE能发的网站,用这个宣传软件就可以仿制动作,进行推送发到您想发送的B2B网站或是信息发布平台上,不管是后台,还是前台,都可以进行最方便的广告发布,这个广告发布软件,可以按月购买,还可以试用软件,对网站的验证码也可以完全自动对信息发布,让客户自动找上门,使企业轻松实现b2b发布,这个信息发布软件,均是本站原创正版开发,拥有正版的血统,想要新功能,欢迎提意见给我,一好的分类信息群发软件在手,舍我其谁。QQ896757558

GMT+8, 2026-9-3 08:09 , Processed in 0.357236 second(s), 51 queries .

宣传软件--信息发布软件--b2b软件广告发布软件

快速回复 返回顶部 返回列表