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

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

[宣传软件网站动态] 悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制

[复制链接]

1975

主题

1985

帖子

1万

积分

积分
11578

资讯缩略图:

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

资讯发布简介:悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制

资讯关键词:悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制

资讯所属分类:IT资讯 

联系:

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

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

资讯详细描述
悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制 悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制 b2b软件

悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制 b2b软件

悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制 b2b软件
  1. /* =============================================================================
  2.    AIWROK 技巧项目 04 —— 悬浮窗控制台(floatUI 可拖动悬浮窗 + 按钮控制)

  3.    作用
  4.    ────
  5.    一个能拖动、能点按钮的悬浮小窗,飘在屏幕最上层:
  6.    ▶启动 / ⏸暂停 / ▶恢复 / ⏹停止 / 收起展开 / ✖关闭,
  7.    后台异步跑多线程任务,窗口实时显示状态。

  8.    这个项目演示的特殊技巧
  9.    ──────────────────────
  10.    1. floatUI 悬浮窗:loadXML 加载布局、findViewById 拿控件、setPosition 定位
  11.    2. 拖动手势:给标题栏挂 OnTouchListener,用 MotionEvent 的 ACTION_DOWN/MOVE/UP
  12.       + getRawX/getRawY 算位移
  13.       ⚠ 真机实测坑:直接写 new View.OnTouchListener(...) 会打印"当前环境不支持拖拽",
  14.         因为短类名 View / MotionEvent 并不是全局可用的。
  15.         正确写法:先 importClass(android.view.View) / importClass(android.view.MotionEvent),
  16.         或用全类名 android.view.View.OnTouchListener、android.view.MotionEvent.ACTION_MOVE。
  17.         本脚本两者都做了(resolveView / resolveMotionEvent),拖不动时还能"点标题栏换位"兜底。
  18.    3. 按钮回调:控件.setOnClickListener(function(){...})
  19.    4. 折叠:View.GONE / View.VISIBLE 控制主体显隐(环境不支持时会自动降级)
  20.    5. 关闭:ui.close(),同时把线程停掉,不留后台野线程
  21.    6. 点击去重:真机上一次点击可能被派发多次(日志里刷 3 条"⏹ 已停止"就是这个原因),
  22.       所以命令要 ① 300ms 同命令去重 ② 池内方法自身幂等,双保险。

  23.    注意
  24.    ────
  25.    本项目的悬浮窗就是"控制台"本身,不是自动弹出来刷屏的日志窗。
  26.    脚本里没有额外弹日志窗,全部日志走 printl 输出到 IDE。
  27.    ============================================================================= */
  28. new floatUI().hideSystemFloat();//隐藏aiwork系统自带的悬浮图标
  29. var CFG = {
  30.     workerCount: 3,
  31.     taskCount: 15,           // 每轮任务数(重启时自动重新装填)
  32.     posX: 40, posY: 220,     // 悬浮窗初始位置
  33.     cmdDebounce: 300         // 同一命令 300ms 内的重复点击直接忽略
  34. };

  35. // ============================== Java 类导入(拖拽必需) ==============================
  36. // 坑:直接写 new View.OnTouchListener(...) 会报"不支持拖拽",
  37. // 因为短类名 View / MotionEvent 并不是全局可用的,必须先 importClass。
  38. try { importClass(android.view.View); } catch (e) {}
  39. try { importClass(android.view.MotionEvent); } catch (e) {}

  40. /** 取 View 类:短名 → 全类名 → null */
  41. function resolveView() {
  42.     if (typeof View !== 'undefined' && View) return View;
  43.     try { if (android && android.view && android.view.View) return android.view.View; } catch (e) {}
  44.     return null;
  45. }

  46. /** 取 MotionEvent 类:短名 → 全类名 → null */
  47. function resolveMotionEvent() {
  48.     if (typeof MotionEvent !== 'undefined' && MotionEvent) return MotionEvent;
  49.     try { if (android && android.view && android.view.MotionEvent) return android.view.MotionEvent; } catch (e) {}
  50.     return null;
  51. }

  52. var ui = null;               // floatUI 实例
  53. var ctrls = {};              // 控件引用
  54. var screenW = 1080, screenH = 1920;
  55. var dragLastX = 0, dragLastY = 0, dragging = false;
  56. var expanded = true;
  57. var winX = CFG.posX, winY = CFG.posY;
  58. var dragEnabled = false;     // 拖拽是否真的绑上了
  59. var lastCmd = { name: '', t: 0 };

  60. // ============================== 工具 ==============================

  61. function log(m) { try { printl(m); } catch (e) {} }
  62. function sleepMs(ms) { try { java.lang.Thread.sleep(ms); } catch (e) {} }
  63. function nowMs() { return java.lang.System.currentTimeMillis(); }

  64. function getScreenSize() {
  65.     try {
  66.         var m = context.getResources().getDisplayMetrics();
  67.         if (m && m.widthPixels) { screenW = m.widthPixels; screenH = m.heightPixels; }
  68.     } catch (e) {
  69.         try { screenW = screen.getScreenWidth(); screenH = screen.getScreenHeight(); } catch (e2) {}
  70.     }
  71.     log('屏幕尺寸: ' + screenW + ' x ' + screenH);
  72. }

  73. // ============================== 后台任务池(精简版) ==============================

  74. function MiniPool(workerCount) {
  75.     var workerN = workerCount || 3;
  76.     var workers = [], queue = [], lock = false;
  77.     var running = false, paused = false, accepting = true;
  78.     var active = 0, total = 0, done = 0, failed = 0;
  79.     var exited = 0;            // 已自然退出的线程数

  80.     function section(fn) {
  81.         var g = 0;
  82.         while (lock && g < 3000) { sleepMs(2); g++; }
  83.         lock = true;
  84.         try { return fn(); } finally { lock = false; }
  85.     }

  86.     function take() {
  87.         var t = null;
  88.         section(function () { if (queue.length > 0) { t = queue.shift(); active++; } });
  89.         return t;
  90.     }

  91.     function loop(idx) {
  92.         while (running) {
  93.             if (paused) { sleepMs(120); continue; }
  94.             var task = take();
  95.             if (task == null) {
  96.                 if (!accepting && queue.length === 0) break;
  97.                 sleepMs(60);
  98.                 continue;
  99.             }
  100.             var ok = true, err = '';
  101.             try { task.fn('T' + idx); } catch (e) { ok = false; err = String(e); }
  102.             section(function () { active--; if (ok) done++; else failed++; });
  103.             consoleLog((ok ? '✔ ' : '✘ ') + 'T' + idx + ' ' + task.name + (ok ? '' : ' ' + err));
  104.         }
  105.         // 关键:线程自然跑完退出时,要把池子状态归位;
  106.         // 否则 running 一直是 true,任务跑完后再点【启动】会被当成"已在运行"而空转。
  107.         section(function () {
  108.             exited++;
  109.             if (exited >= workerN) { running = false; paused = false; accepting = true; }
  110.         });
  111.     }

  112.     this.add = function (name, fn) { section(function () { queue.push({ name: name, fn: fn }); total++; }); return this; };

  113.     /** 本轮是否已跑完 */
  114.     this.isFinished = function () { return total > 0 && (done + failed) >= total; };

  115.     /** 清空队列与计数(只能在没有线程运行时调用) */
  116.     this.reset = function () {
  117.         if (running || active > 0) return false;
  118.         section(function () {
  119.             queue = []; total = 0; done = 0; failed = 0; exited = 0; accepting = true; paused = false;
  120.         });
  121.         return true;
  122.     };

  123.     // 所有控制方法都要幂等:重复点击只提示、不重复执行、不重复打日志
  124.     this.start = function () {
  125.         if (running) { consoleLog('· 已经在运行了'); return false; }
  126.         if (queue.length === 0) { consoleLog('· 队列是空的,先装任务'); return false; }
  127.         running = true; paused = false; accepting = true; exited = 0;
  128.         for (var i = 0; i < workerN; i++) {
  129.             var th = new thread();
  130.             workers.push(th);
  131.             (function (n) { th.runJsCode(function () { loop(n); }, '悬浮台线程' + n); })(i + 1);
  132.             sleepMs(140);
  133.         }
  134.         consoleLog('▶ 已启动 ' + workerN + ' 个线程');
  135.         return true;
  136.     };

  137.     this.pause = function () {
  138.         if (!running) { consoleLog('· 没在运行,不用暂停'); return false; }
  139.         if (paused) { consoleLog('· 已经是暂停状态'); return false; }
  140.         paused = true;
  141.         consoleLog('⏸ 已暂停');
  142.         return true;
  143.     };

  144.     this.resume = function () {
  145.         if (!paused) { consoleLog('· 当前不是暂停状态'); return false; }
  146.         paused = false;
  147.         consoleLog('▶ 已恢复');
  148.         return true;
  149.     };

  150.     this.stop = function () {
  151.         // 幂等:确实没东西在跑就什么都不做("⏹ 已停止"刷 3 条就是这么来的)
  152.         var inf = this.info();
  153.         if (!inf.running && inf.alive === 0 && inf.active === 0) {
  154.             consoleLog('· 已经停止了');
  155.             return false;
  156.         }
  157.         accepting = false; running = false; paused = false;
  158.         for (var i = 0; i < workers.length; i++) {
  159.             try { if (workers[i].isAlive()) workers[i].stop(); } catch (e) {}
  160.         }
  161.         exited = 0;
  162.         consoleLog('⏹ 已停止');
  163.         return true;
  164.     };

  165.     this.info = function () {
  166.         var a = 0;
  167.         for (var i = 0; i < workers.length; i++) { try { if (workers[i].isAlive()) a++; } catch (e) {} }
  168.         return { total: total, done: done, failed: failed, queue: queue.length, active: active, alive: a, paused: paused, running: running };
  169.     };
  170. }

  171. var pool = null;

  172. // ============================== 窗口内的状态显示 ==============================

  173. var consoleLines = [];

  174. function consoleLog(text) {
  175.     var n = new Date();
  176.     var t = ('0' + n.getHours()).slice(-2) + ':' + ('0' + n.getMinutes()).slice(-2) + ':' + ('0' + n.getSeconds()).slice(-2);
  177.     consoleLines.unshift('[' + t + '] ' + text);
  178.     if (consoleLines.length > 4) consoleLines = consoleLines.slice(0, 4);
  179.     log(text);
  180.     // 注意:这里不直接刷控件。控件更新统一放到主线程心跳里做,
  181.     // 避免工作线程直接操作 UI 触发 Android 的 "only the original thread can touch its views" 异常。
  182. }

  183. function renderConsole() {
  184.     try {
  185.         if (ctrls.log) ctrls.log.setText(consoleLines.join('\n'));
  186.     } catch (e) {}
  187. }

  188. function refreshStatus() {
  189.     if (!pool) return;
  190.     var i = pool.info();
  191.     var pct = i.total > 0 ? Math.floor((i.done + i.failed) * 100 / i.total) : 0;
  192.     var txt = '进度 ' + pct + '%   ✔' + i.done + '  ✘' + i.failed +
  193.               '  队列' + i.queue + '  线程' + i.alive;
  194.     try { if (ctrls.status) ctrls.status.setText(txt); } catch (e) {}
  195. }

  196. // ============================== 浮动窗口 ==============================

  197. function buildXml() {
  198.     return '' +
  199.     '<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ' +
  200.     '  android:id="box" android:layout_width="230dp" android:layout_height="wrap_content" ' +
  201.     '  android:orientation="vertical" android:background="#E6111A2B" android:padding="6dp">' +

  202.     '  <LinearLayout android:id="title" android:layout_width="match_parent" ' +
  203.     '    android:layout_height="34dp" android:orientation="horizontal" android:gravity="center_vertical" ' +
  204.     '    android:background="#1F2A44">' +
  205.     '    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" ' +
  206.     '      android:text="✥" android:textColor="#8FA3C8" android:textSize="15sp" android:paddingLeft="6dp" android:paddingRight="6dp"/>' +
  207.     '    <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" ' +
  208.     '      android:text="AIWROK 控制台" android:textColor="#FFFFFF" android:textSize="13sp"/>' +
  209.     '    <Button android:id="btnFold" android:layout_width="34dp" android:layout_height="28dp" ' +
  210.     '      android:text="-" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#334155" android:padding="0dp"/>' +
  211.     '    <Button android:id="btnClose" android:layout_width="34dp" android:layout_height="28dp" ' +
  212.     '      android:text="✕" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#EF4444" android:padding="0dp"/>' +
  213.     '  </LinearLayout>' +

  214.     '  <LinearLayout android:id="body" android:layout_width="match_parent" ' +
  215.     '    android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="6dp">' +

  216.     '    <TextView android:id="status" android:layout_width="match_parent" android:layout_height="wrap_content" ' +
  217.     '      android:text="进度 0%   ✔0  ✘0  队列0  线程0" android:textColor="#60A5FA" android:textSize="11sp" android:paddingBottom="6dp"/>' +

  218.     '    <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" ' +
  219.     '      android:orientation="horizontal">' +
  220.     '      <Button android:id="btnStart" android:layout_width="0dp" android:layout_weight="1" ' +
  221.     '        android:layout_height="36dp" android:text="▶ 启动" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#16A34A" android:padding="0dp"/>' +
  222.     '      <Button android:id="btnPause" android:layout_width="0dp" android:layout_weight="1" ' +
  223.     '        android:layout_height="36dp" android:text="⏸ 暂停" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#D97706" android:padding="0dp"/>' +
  224.     '    </LinearLayout>' +

  225.     '    <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" ' +
  226.     '      android:orientation="horizontal" android:paddingTop="4dp">' +
  227.     '      <Button android:id="btnResume" android:layout_width="0dp" android:layout_weight="1" ' +
  228.     '        android:layout_height="36dp" android:text="▶ 恢复" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#2563EB" android:padding="0dp"/>' +
  229.     '      <Button android:id="btnStop" android:layout_width="0dp" android:layout_weight="1" ' +
  230.     '        android:layout_height="36dp" android:text="⏹ 停止" android:textColor="#FFFFFF" android:textSize="12sp" android:background="#B91C1C" android:padding="0dp"/>' +
  231.     '    </LinearLayout>' +

  232.     '    <TextView android:id="log" android:layout_width="match_parent" android:layout_height="wrap_content" ' +
  233.     '      android:text="" android:textColor="#86EFAC" android:textSize="10sp" android:paddingTop="6dp"/>' +
  234.     '  </LinearLayout>' +
  235.     '</LinearLayout>';
  236. }

  237. function moveTo(x, y) {
  238.     if (x < 0) x = 0;
  239.     if (y < 0) y = 0;
  240.     if (x > screenW - 120) x = screenW - 120;
  241.     if (y > screenH - 80) y = screenH - 80;
  242.     winX = x; winY = y;
  243.     try { ui.setPosition(x, y); } catch (e) {}
  244. }

  245. /** 绑定拖拽。设备实测:短类名 View/MotionEvent 不存在 → 必须用 importClass 后的类 */
  246. function setupDrag() {
  247.     var V = resolveView();
  248.     var M = resolveMotionEvent();
  249.     if (!V || !M || !ctrls.title || !ctrls.title.setOnTouchListener) {
  250.         log('⚠ 拖拽不可用(缺 ' + (V ? '' : 'View ') + (M ? '' : 'MotionEvent') + '),改用【点标题栏换位】');
  251.         bindTitleTapToMove();
  252.         return false;
  253.     }
  254.     try {
  255.         ctrls.title.setOnTouchListener(new V.OnTouchListener({
  256.             onTouch: function (view, event) {
  257.                 try {
  258.                     switch (event.getAction()) {
  259.                         case M.ACTION_DOWN:
  260.                             dragging = true;
  261.                             dragLastX = event.getRawX();
  262.                             dragLastY = event.getRawY();
  263.                             break;
  264.                         case M.ACTION_MOVE:
  265.                             if (dragging) {
  266.                                 var dx = event.getRawX() - dragLastX;
  267.                                 var dy = event.getRawY() - dragLastY;
  268.                                 moveTo(winX + dx, winY + dy);
  269.                                 dragLastX = event.getRawX();
  270.                                 dragLastY = event.getRawY();
  271.                             }
  272.                             break;
  273.                         case M.ACTION_UP:
  274.                             dragging = false;
  275.                             break;
  276.                     }
  277.                     return true;
  278.                 } catch (e2) { return false; }
  279.             }
  280.         }));
  281.         dragEnabled = true;
  282.         log('✔ 拖拽已绑定:按住标题栏可移动窗口');
  283.         return true;
  284.     } catch (e) {
  285.         log('⚠ 拖拽绑定失败: ' + e);
  286.         bindTitleTapToMove();
  287.         return false;
  288.     }
  289. }

  290. /** 拖拽不可用时的兜底:点一下标题栏,在几个预设位置间循环 */
  291. var presetIdx = -1;
  292. function bindTitleTapToMove() {
  293.     if (!ctrls.title || !ctrls.title.setOnClickListener) return;
  294.     try {
  295.         ctrls.title.setOnClickListener(function () {
  296.             var presets = [
  297.                 [20, 160], [Math.floor(screenW * 0.5) - 115, 160],
  298.                 [screenW - 250, 160], [screenW - 250, Math.floor(screenH * 0.5)],
  299.                 [20, Math.floor(screenH * 0.6)]
  300.             ];
  301.             presetIdx = (presetIdx + 1) % presets.length;
  302.             moveTo(presets[presetIdx][0], presets[presetIdx][1]);
  303.             log('↔ 窗口已换位到第 ' + (presetIdx + 1) + ' 个位置');
  304.         });
  305.     } catch (e) {}
  306. }

  307. function toggleFold() {
  308.     expanded = !expanded;
  309.     var V = resolveView();
  310.     try {
  311.         if (V && V.GONE !== undefined && ctrls.body && ctrls.body.setVisibility) {
  312.             ctrls.body.setVisibility(expanded ? V.VISIBLE : V.GONE);
  313.             log(expanded ? '&#128316; 已展开' : '&#128317; 已收起');
  314.             return true;
  315.         }
  316.     } catch (e) {}
  317.     expanded = true;
  318.     log('⚠ 当前环境不支持折叠,窗口保持展开');
  319.     return false;
  320. }

  321. function closeConsole() {
  322.     log('✖ 关闭控制台');
  323.     try { pool.stop(); } catch (e) {}
  324.     try { ui.close(); } catch (e) { log('关闭悬浮窗失败: ' + e); }
  325.     alive = false;
  326. }

  327. // ============================== 命令分发(去重 + 立即刷界面) ==============================
  328. // 实测发现:一次点击可能被派发多次(3 条一模一样的"已停止"就是这么来的)。
  329. // 双保险:① 同一命令 300ms 内只认第一次;② MiniPool 内部各方法本身幂等。

  330. function onceCmd(name) {
  331.     var t = nowMs();
  332.     if (name === lastCmd.name && t - lastCmd.t < CFG.cmdDebounce) return false;
  333.     lastCmd = { name: name, t: t };
  334.     return true;
  335. }

  336. /** 按钮回调跑在 UI 线程,这里直接刷控件是安全的,点完立刻能看到变化 */
  337. function afterCmd() {
  338.     refreshStatus();
  339.     renderConsole();
  340. }

  341. function cmdStart() {
  342.     if (!onceCmd('start')) return;
  343.     if (pool.isFinished()) {                 // 上一轮已跑完 → 自动重新装填,避免"重启空跑"
  344.         pool.reset();
  345.         refillTasks();
  346.         consoleLog('&#128260; 已重新装填 ' + CFG.taskCount + ' 个任务');
  347.     }
  348.     pool.start();
  349.     afterCmd();
  350. }

  351. function cmdPause()  { if (!onceCmd('pause'))  return; pool.pause();  afterCmd(); }
  352. function cmdResume() { if (!onceCmd('resume')) return; pool.resume(); afterCmd(); }
  353. function cmdStop()   { if (!onceCmd('stop'))   return; pool.stop();   afterCmd(); }
  354. function cmdFold()   { if (!onceCmd('fold'))   return; toggleFold();  afterCmd(); }
  355. function cmdClose()  { if (!onceCmd('close'))  return; closeConsole(); }

  356. // ============================== 界面装配 ==============================

  357. var alive = true;

  358. function createConsole() {
  359.     getScreenSize();
  360.     ui = new floatUI();
  361.     ui.loadXML(buildXml());

  362.     ctrls.title     = ui.findViewById('title');
  363.     ctrls.body      = ui.findViewById('body');
  364.     ctrls.status    = ui.findViewById('status');
  365.     ctrls.log       = ui.findViewById('log');
  366.     ctrls.btnStart  = ui.findViewById('btnStart');
  367.     ctrls.btnPause  = ui.findViewById('btnPause');
  368.     ctrls.btnResume = ui.findViewById('btnResume');
  369.     ctrls.btnStop   = ui.findViewById('btnStop');
  370.     ctrls.btnFold   = ui.findViewById('btnFold');
  371.     ctrls.btnClose  = ui.findViewById('btnClose');

  372.     if (!ctrls.btnStart) { log('✘ 悬浮窗控件未取到,设备可能不支持 floatUI'); return false; }

  373.     // 按钮事件(统一走 cmd* 分发器:带去重 + 幂等 + 立即刷界面)
  374.     ctrls.btnStart.setOnClickListener(function () { try { cmdStart(); } catch (e) { log('启动失败: ' + e); } });
  375.     ctrls.btnPause.setOnClickListener(function () { try { cmdPause(); } catch (e) {} });
  376.     ctrls.btnResume.setOnClickListener(function () { try { cmdResume(); } catch (e) {} });
  377.     ctrls.btnStop.setOnClickListener(function () { try { cmdStop(); } catch (e) {} });
  378.     ctrls.btnFold.setOnClickListener(function () { try { cmdFold(); } catch (e) {} });
  379.     ctrls.btnClose.setOnClickListener(function () { try { cmdClose(); } catch (e) {} });

  380.     setupDrag();
  381.     moveTo(CFG.posX, CFG.posY);
  382.     consoleLog('控制台就绪,点【▶ 启动】跑任务');
  383.     return true;
  384. }

  385. // ============================== 任务与心跳 ==============================

  386. function buildTask(idx) {
  387.     return function (tag) {
  388.         sleepMs(rand.randNumber(400, 1200));
  389.         if (idx % 8 === 0) throw new Error('第' + idx + '个任务异常');
  390.     };
  391. }

  392. /** 装填一轮任务 */
  393. function refillTasks() {
  394.     for (var i = 1; i <= CFG.taskCount; i++) pool.add('任务' + i, buildTask(i));
  395. }

  396. /** 心跳(跑在主线程):刷新窗口状态 + 给主线程保活 */
  397. function heartbeat() {
  398.     if (!alive) { log('心跳结束,主线程退出'); return; }
  399.     refreshStatus();
  400.     renderConsole();
  401.     runTime.setTimeout(heartbeat, 1000);
  402. }

  403. // ============================== 入口 ==============================

  404. function main() {
  405.     log('════════════════════════════════════════════');
  406.     log('  悬浮窗控制台(floatUI)');
  407.     log('════════════════════════════════════════════');

  408.     pool = new MiniPool(CFG.workerCount);
  409.     refillTasks();

  410.     if (!createConsole()) return;

  411.     heartbeat();
  412.     log(dragEnabled ? '&#128073; 按住标题栏拖动窗口' : '&#128073; 点标题栏可循环换位');
  413.     log('   【▶ 启动】跑任务  【⏸ 暂停】/【▶ 恢复】  【⏹ 停止】  【-】收起  【✕】关闭');
  414.     log('   任务跑完后再点【▶ 启动】会自动重新装填一轮');
  415. }

  416. main();
复制代码






unto日志分级落盘配置持久化任务调度nextnocontent
回复

使用道具 举报

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

本版积分规则

相关导读
群发软件悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制
悬浮窗控制台floatUI 可拖动悬浮窗 + 按钮控制
群发软件日志分级落盘配置持久化任务调度
日志分级落盘配置持久化任务调度
群发软件贝塞尔曲线滑动的实际演示
贝塞尔曲线滑动的实际演示
群发软件通用找图OCR点字完整脚本骨架
通用找图OCR点字完整脚本骨架
群发软件AIWROK函数没定义就调用脚本直接崩
AIWROK函数没定义就调用脚本直接崩
群发软件本地部署局域网内YOLO自动识别快手图标
本地部署局域网内YOLO自动识别快手图标
群发软件MQTT远程本地局域网OCR例子
MQTT远程本地局域网OCR例子
群发软件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方法完整示例
群发软件安卓脚本暂停弹出确认对话框
安卓脚本暂停弹出确认对话框

QQ|( 京ICP备09078825号 )

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

GMT+8, 2026-9-14 07:40 , Processed in 0.158368 second(s), 49 queries .

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

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