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

[24小时收录超级好的网站] adb.exec() 高级用法完整示例

[复制链接]

2598

主题

2646

帖子

1万

积分

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


adb.exec() 高级用法完整示例
adb.exec() 高级用法完整示例 群发软件发帖工具

adb.exec() 高级用法完整示例 群发软件发帖工具




  1. // =============================================================================
  2. // AIWROK adb.exec() 高级用法完整示例
  3. // =============================================================================
  4. // 适用平台:AIWROK 安卓自动化软件
  5. // 引擎:Rhino (ES5)
  6. // 说明:adb.exec(command, isRoot) 是 AIWROK 提供的 ADB 命令执行接口
  7. //   - 参数1 (command):要执行的 shell 命令字符串
  8. //   - 参数2 (isRoot):boolean,true=以 root 权限执行(su -c),false=普通权限执行
  9. //   - 返回值:JSON 格式 {"errorMsg":"","success":"实际内容"},需提取 success 字段
  10. //
  11. // 与 agent.shell() 的区别:
  12. //   - agent.shell() 仅在代理模式下可用,需要 root 或 PC_ADB 连接
  13. //   - adb.exec() 可直接在设备端执行,isRoot 参数灵活控制权限
  14. //   - adb.exec() 返回值需要清洗,agent.shell() 返回值相对干净
  15. // =============================================================================

  16. print.log("===== adb.exec() 高级用法完整示例 =====\n");

  17. // =============================================================================
  18. // 工具函数:清洗 adb.exec 返回值
  19. // =============================================================================
  20. // adb.exec() 实际返回 JSON 格式: {"errorMsg":"","success":"实际内容"}
  21. // 需要提取 success 字段的值,并处理转义字符
  22. function 清洗输出(原始结果) {
  23.     if (!原始结果) return "";
  24.     var 结果 = String(原始结果);

  25.     // 格式1: JSON 格式 {"errorMsg":"","success":"实际内容"}
  26.     if (结果.charAt(0) === "{") {
  27.         try {
  28.             var json = JSON.parse(结果);
  29.             if (json && json.success !== undefined) {
  30.                 // 检查是否有错误
  31.                 if (json.errorMsg && json.errorMsg !== "") {
  32.                     print.log("⚠ 命令返回错误: " + json.errorMsg);
  33.                 }
  34.                 return String(json.success).trim();
  35.             }
  36.         } catch (e) {
  37.             // JSON.parse 失败,尝试正则提取 success 字段
  38.             var successMatch = 结果.match(/"success"\s*:\s*"([\s\S]*?)"\s*[,}]/);
  39.             if (successMatch) {
  40.                 return successMatch[1]
  41.                     .replace(/\\n/g, "\n")
  42.                     .replace(/\\t/g, "\t")
  43.                     .replace(/\\"/g, '"')
  44.                     .replace(/\\\\/g, "\\")
  45.                     .trim();
  46.             }
  47.         }
  48.         return 结果.trim();
  49.     }

  50.     // 格式2: 旧格式 successMsg:内容,errorMsg:内容(兼容 agent.shell)
  51.     if (结果.indexOf("successMsg:") === 0) {
  52.         结果 = 结果.substring("successMsg:".length);
  53.     }
  54.     var 错误索引 = 结果.indexOf(",errorMsg:");
  55.     if (错误索引 !== -1) {
  56.         结果 = 结果.substring(0, 错误索引);
  57.     }
  58.     return 结果.trim();
  59. }

  60. // 工具函数:安全执行命令并返回清洗后的结果
  61. function 执行命令(命令, 是否root) {
  62.     try {
  63.         var 原始 = adb.exec(命令, 是否root || false);
  64.         return 清洗输出(String(原始));
  65.     } catch (e) {
  66.         print.log("⚠ 命令执行异常 [" + 命令 + "]: " + e.message);
  67.         return "";
  68.     }
  69. }

  70. // 工具函数:安全执行命令(不关心返回值,只关心是否成功)
  71. function 执行命令静默(命令, 是否root) {
  72.     try {
  73.         adb.exec(命令, 是否root || false);
  74.         return true;
  75.     } catch (e) {
  76.         print.log("⚠ 命令执行异常 [" + 命令 + "]: " + e.message);
  77.         return false;
  78.     }
  79. }

  80. // =============================================================================
  81. // 工具函数:3秒倒计时(每个动作前执行,增加节奏感)
  82. // =============================================================================
  83. function 倒计时(秒数, 提示) {
  84.     秒数 = 秒数 || 3;
  85.     提示 = 提示 || "";
  86.     for (var i = 秒数; i > 0; i--) {
  87.         print.log("⏳ " + 提示 + " 倒计时: " + i + " 秒...");
  88.         sleep.second(1);
  89.     }
  90.     print.log("▶ " + 提示 + " 开始执行");
  91. }


  92. // =============================================================================
  93. // 第一部分:基础文件操作
  94. // =============================================================================
  95. 倒计时(3, "第一部分:基础文件操作");
  96. print.log("========== 第一部分:基础文件操作 ==========\n");

  97. // 1.1 列出目录内容(非 root)
  98. print.log("--- 1.1 列出 /sdcard/ 目录内容 ---");
  99. var 目录列表 = 执行命令("ls -la /sdcard/", false);
  100. print.log("目录内容:\n" + 目录列表);

  101. // 1.2 列出指定目录并过滤(结合 grep 管道,注意不能用 grep -P)
  102. print.log("\n--- 1.2 列出 /sdcard/ 下的 .png 文件 ---");
  103. var 图片列表 = 执行命令("ls /sdcard/*.png 2>/dev/null", false);
  104. print.log("PNG 文件:\n" + (图片列表 || "无"));

  105. // 1.3 查看文件内容
  106. print.log("\n--- 1.3 查看 /sdcard/test.txt 文件内容 ---");
  107. var 文件内容 = 执行命令("cat /sdcard/test.txt 2>/dev/null", false);
  108. print.log("文件内容:\n" + (文件内容 || "文件不存在或为空"));

  109. // 1.4 创建目录(需要 root 时操作 /data 等系统目录)
  110. print.log("\n--- 1.4 创建目录 ---");
  111. 执行命令静默("mkdir -p /sdcard/aiwrok_test", false);
  112. print.log("✓ 已创建 /sdcard/aiwrok_test 目录");

  113. // 1.5 复制文件
  114. print.log("\n--- 1.5 复制文件 ---");
  115. 执行命令静默("cp /sdcard/test.txt /sdcard/aiwrok_test/test_backup.txt 2>/dev/null", false);
  116. print.log("✓ 已复制文件");

  117. // 1.6 写入文件(通过 echo 重定向)
  118. print.log("\n--- 1.6 通过 echo 写入文件 ---");
  119. 执行命令静默("echo 'AIWROK adb.exec 测试写入' > /sdcard/aiwrok_test/write_test.txt", false);
  120. var 写入验证 = 执行命令("cat /sdcard/aiwrok_test/write_test.txt", false);
  121. print.log("写入验证:" + 写入验证);

  122. // 1.7 获取文件大小和权限信息
  123. print.log("\n--- 1.7 获取文件详细信息 ---");
  124. var 文件信息 = 执行命令("ls -l /sdcard/aiwrok_test/write_test.txt", false);
  125. print.log("文件信息:" + 文件信息);

  126. // 1.8 统计目录下文件数量
  127. print.log("\n--- 1.8 统计 /sdcard/ 下文件数量 ---");
  128. var 文件数 = 执行命令("ls /sdcard/ | wc -l", false);
  129. print.log("文件数量:" + 文件数);


  130. // =============================================================================
  131. // 第二部分:应用管理(Package Manager)
  132. // =============================================================================
  133. 倒计时(3, "第二部分:应用管理");
  134. print.log("\n========== 第二部分:应用管理 ==========\n");

  135. // 2.1 列出所有已安装的第三方应用
  136. print.log("--- 2.1 列出所有第三方应用包名 ---");
  137. var 第三方应用 = 执行命令("pm list packages -3", false);
  138. var 应用数组 = 第三方应用 ? 第三方应用.split("\n") : [];
  139. print.log("第三方应用数量:" + 应用数组.length);
  140. // 只打印前5个
  141. for (var i = 0; i < Math.min(5, 应用数组.length); i++) {
  142.     print.log("  " + 应用数组[i]);
  143. }
  144. if (应用数组.length > 5) {
  145.     print.log("  ... 共 " + 应用数组.length + " 个应用");
  146. }

  147. // 2.2 列出所有系统应用
  148. print.log("\n--- 2.2 列出系统应用数量 ---");
  149. var 系统应用 = 执行命令("pm list packages -s", false);
  150. var 系统应用数组 = 系统应用 ? 系统应用.split("\n") : [];
  151. print.log("系统应用数量:" + 系统应用数组.length);

  152. // 2.3 查看指定应用信息
  153. print.log("\n--- 2.3 查看微信应用信息 ---");
  154. var 微信信息 = 执行命令("pm list packages com.tencent.mm", false);
  155. print.log("微信包名信息:" + (微信信息 || "未安装微信"));

  156. // 2.4 启动应用(通过 am start)
  157. print.log("\n--- 2.4 启动指定应用 ---");
  158. // 启动设置应用
  159. 执行命令静默("am start -a android.settings.SETTINGS", false);
  160. print.log("✓ 已启动系统设置");

  161. // 2.5 通过 monkey 启动应用
  162. print.log("\n--- 2.5 通过 monkey 启动应用 ---");
  163. // 执行命令静默("monkey -p com.tencent.mm 1", false);
  164. print.log("(示例)可通过 monkey -p <包名> 1 启动应用");

  165. // 2.6 强制停止应用
  166. print.log("\n--- 2.6 强制停止应用 ---");
  167. // 执行命令静默("am force-stop com.tencent.mm", false);
  168. print.log("(示例)可通过 am force-stop <包名> 强制停止应用");

  169. // 2.7 清除应用数据(需要 root 或对应权限)
  170. print.log("\n--- 2.7 清除应用数据(root 示例)---");
  171. // adb.exec("pm clear com.example.app", true);  // true = root 权限
  172. print.log("(示例)adb.exec('pm clear com.example.app', true) 以 root 清除应用数据");

  173. // 2.8 安装 / 卸载 APK
  174. print.log("\n--- 2.8 安装/卸载 APK ---");
  175. // 安装:adb.exec("pm install /sdcard/app.apk", false);
  176. // 卸载:adb.exec("pm uninstall com.example.app", false);
  177. print.log("(示例)pm install / pm uninstall 可安装/卸载应用");


  178. // =============================================================================
  179. // 第三部分:系统信息获取
  180. // =============================================================================
  181. 倒计时(3, "第三部分:系统信息获取");
  182. print.log("\n========== 第三部分:系统信息获取 ==========\n");

  183. // 3.1 获取系统属性(getprop)
  184. print.log("--- 3.1 获取设备系统属性 ---");
  185. var 设备型号 = 执行命令("getprop ro.product.model", false);
  186. var 安卓版本 = 执行命令("getprop ro.build.version.release", false);
  187. var SDK版本 = 执行命令("getprop ro.build.version.sdk", false);
  188. var 制造商 = 执行命令("getprop ro.product.manufacturer", false);
  189. var 序列号 = 执行命令("getprop ro.serialno", false);
  190. print.log("设备型号:" + 设备型号);
  191. print.log("安卓版本:" + 安卓版本);
  192. print.log("SDK版本:" + SDK版本);
  193. print.log("制造商:" + 制造商);
  194. print.log("序列号:" + 序列号);

  195. // 3.2 获取屏幕分辨率
  196. print.log("\n--- 3.2 获取屏幕分辨率 ---");
  197. var 分辨率 = 执行命令("wm size", false);
  198. print.log("屏幕分辨率:" + 分辨率);
  199. var 密度 = 执行命令("wm density", false);
  200. print.log("屏幕密度:" + 密度);

  201. // 3.3 获取电池信息(多策略:sysfs → dumpsys解析 → bms回退)
  202. print.log("\n--- 3.3 获取电池信息 ---");
  203. var 电池信息3 = 获取电池信息();
  204. print.log("电池电量:" + (电池信息3.电量 || "未知") + "%");
  205. print.log("电池状态:" + (电池信息3.状态 || "未知"));
  206. print.log("电池温度:" + (电池信息3.温度 || "未知"));
  207. print.log("电池技术:" + (电池信息3.技术 || "未知"));

  208. // 3.4 获取内存信息
  209. print.log("\n--- 3.4 获取内存信息 ---");
  210. var 内存信息 = 执行命令("cat /proc/meminfo | head -5", false);
  211. print.log("内存信息:\n" + 内存信息);

  212. // 3.5 获取 CPU 信息
  213. print.log("\n--- 3.5 获取 CPU 信息 ---");
  214. var CPU信息 = 执行命令("cat /proc/cpuinfo | head -10", false);
  215. print.log("CPU信息:\n" + CPU信息);

  216. // 3.6 获取存储信息
  217. print.log("\n--- 3.6 获取存储信息 ---");
  218. var 存储信息 = 执行命令("df /sdcard", false);
  219. print.log("存储信息:\n" + 存储信息);

  220. // 3.7 获取网络连接信息
  221. print.log("\n--- 3.7 获取网络信息 ---");
  222. var IP地址 = 执行命令("ip addr show wlan0 | grep 'inet '", false);
  223. print.log("IP地址:" + IP地址);
  224. // WiFi状态:管道grep返回空,改用JS解析 dumpsys wifi 完整输出
  225. var WiFi完整 = 执行命令("dumpsys wifi 2>/dev/null", false);
  226. var WiFi状态 = "未知";
  227. if (WiFi完整 && WiFi完整.length > 0) {
  228.     var WiFi行 = WiFi完整.split("\n");
  229.     for (var wi = 0; wi < WiFi行.length; wi++) {
  230.         var 行内容 = WiFi行[wi].trim().toLowerCase();
  231.         if (行内容.indexOf("wi-fi is") !== -1 || 行内容.indexOf("wifi is") !== -1) {
  232.             WiFi状态 = WiFi行[wi].trim();
  233.             break;
  234.         }
  235.     }
  236.     // 回退:搜索 "Wi-Fi" 关键字所在行
  237.     if (WiFi状态 === "未知") {
  238.         for (var wi2 = 0; wi2 < WiFi行.length; wi2++) {
  239.             if (WiFi行[wi2].toLowerCase().indexOf("wifi") !== -1 && WiFi行[wi2].indexOf("SSID") !== -1) {
  240.                 WiFi状态 = WiFi行[wi2].trim();
  241.                 break;
  242.             }
  243.         }
  244.     }
  245. }
  246. print.log("WiFi状态:" + WiFi状态);


  247. // =============================================================================
  248. // 第四部分:输入模拟(Input Commands)
  249. // =============================================================================
  250. 倒计时(3, "第四部分:输入模拟");
  251. print.log("\n========== 第四部分:输入模拟 ==========\n");

  252. // 4.1 模拟点击(input tap)
  253. print.log("--- 4.1 模拟点击坐标 ---");
  254. // 执行命令静默("input tap 540 960", false);
  255. print.log("(示例)input tap 540 960 → 点击屏幕中心");

  256. // 4.2 模拟滑动(input swipe)
  257. print.log("\n--- 4.2 模拟滑动 ---");
  258. // 执行命令静默("input swipe 540 1500 540 500 300", false);  // 上滑
  259. print.log("(示例)input swipe 540 1500 540 500 300 → 向上滑动");

  260. // 4.3 模拟长按(swipe 起点终点相同,时长 > 500ms)
  261. print.log("\n--- 4.3 模拟长按 ---");
  262. // 执行命令静默("input swipe 540 960 540 960 1000", false);
  263. print.log("(示例)input swipe 540 960 540 960 1000 → 长按 1 秒");

  264. // 4.4 模拟输入文字(仅支持 ASCII)
  265. print.log("\n--- 4.4 模拟输入文字 ---");
  266. // 执行命令静默("input text 'hello123'", false);
  267. print.log("(示例)input text 'hello123' → 输入 ASCII 文字");

  268. // 4.5 模拟按键事件(input keyevent)
  269. print.log("\n--- 4.5 模拟按键事件 ---");
  270. var 按键说明 = {
  271.     "3": "KEYCODE_HOME (Home键)",
  272.     "4": "KEYCODE_BACK (返回键)",
  273.     "24": "KEYCODE_VOLUME_UP (音量加)",
  274.     "25": "KEYCODE_VOLUME_DOWN (音量减)",
  275.     "26": "KEYCODE_POWER (电源键)",
  276.     "27": "KEYCODE_CAMERA (相机键)",
  277.     "66": "KEYCODE_ENTER (回车键)",
  278.     "82": "KEYCODE_MENU (菜单键)",
  279.     "279": "KEYCODE_PASTE (粘贴键)"
  280. };
  281. for (var 键码 in 按键说明) {
  282.     // 执行命令静默("input keyevent " + 键码, false);
  283.     print.log("  keyevent " + 键码 + " → " + 按键说明[键码]);
  284. }

  285. // 4.6 模拟组合键(Ctrl+V 粘贴)
  286. print.log("\n--- 4.6 模拟组合键 ---");
  287. // 执行命令静默("input keyevent 50 --meta 0x1000", false);  // Ctrl+V
  288. print.log("(示例)input keyevent 50 --meta 0x1000 → Ctrl+V 粘贴");


  289. // =============================================================================
  290. // 第五部分:截图与媒体控制
  291. // =============================================================================
  292. 倒计时(3, "第五部分:截图与媒体控制");
  293. print.log("\n========== 第五部分:截图与媒体控制 ==========\n");

  294. // 5.1 截图保存到文件
  295. print.log("--- 5.1 截图保存到文件 ---");
  296. var 截图路径 = "/sdcard/aiwrok_test/screenshot_" + Date.now() + ".png";
  297. 执行命令静默("screencap -p " + 截图路径, false);
  298. var 截图验证 = 执行命令("ls -l " + 截图路径, false);
  299. print.log("截图文件:" + 截图验证);

  300. // 5.2 截图直接输出到 stdout(用于获取二进制数据)
  301. print.log("\n--- 5.2 截图输出到 stdout ---");
  302. print.log("(示例)screencap -p 可直接输出 PNG 数据流");

  303. // 5.3 录屏(需要 Android 4.4+)
  304. print.log("\n--- 5.3 录屏命令 ---");
  305. print.log("(示例)screenrecord --time-limit 10 /sdcard/aiwrok_test/record.mp4 → 录屏10秒");

  306. // 5.4 媒体音量控制(管道grep返回空,改用JS解析)
  307. print.log("\n--- 5.4 媒体音量控制 ---");
  308. var 音频完整 = 执行命令("dumpsys audio 2>/dev/null", false);
  309. var 音量输出 = "";
  310. if (音频完整 && 音频完整.length > 0) {
  311.     var 音频行 = 音频完整.split("\n");
  312.     var 音量行 = [];
  313.     for (var ai = 0; ai < 音频行.length; ai++) {
  314.         if (音频行[ai].indexOf("Stream volume") !== -1 || 音频行[ai].indexOf("STREAM_MUSIC") !== -1) {
  315.             音量行.push(音频行[ai].trim());
  316.         }
  317.     }
  318.     音量输出 = 音量行.length > 0 ? 音量行.join("\n") : "未找到音量信息";
  319. } else {
  320.     音量输出 = "dumpsys audio 不可用";
  321. }
  322. print.log("当前音频流信息:\n" + 音量输出);


  323. // =============================================================================
  324. // 第六部分:进程管理
  325. // =============================================================================
  326. 倒计时(3, "第六部分:进程管理");
  327. print.log("\n========== 第六部分:进程管理 ==========\n");

  328. // 6.1 查看所有运行中的进程
  329. print.log("--- 6.1 查看运行中的进程(前10个)---");
  330. var 进程列表 = 执行命令("ps | head -10", false);
  331. print.log("进程列表:\n" + 进程列表);

  332. // 6.2 查找特定进程
  333. print.log("\n--- 6.2 查找特定进程 ---");
  334. // 注意:Android shell 不支持 grep -P,使用普通 grep
  335. var 微信进程 = 执行命令("ps | grep com.tencent.mm", false);
  336. print.log("微信进程:" + (微信进程 || "微信未运行"));

  337. // 6.3 获取 CPU 占用最高的进程
  338. print.log("\n--- 6.3 CPU 占用最高的进程 ---");
  339. var CPU占用 = 执行命令("top -n 1 -b | head -15", false);
  340. print.log("CPU占用情况:\n" + CPU占用);

  341. // 6.4 杀死进程(需要 root 或同 UID)
  342. print.log("\n--- 6.4 杀死进程 ---");
  343. // 执行命令静默("kill <PID>", true);  // 需要 root
  344. print.log("(示例)kill <PID> 以 root 权限杀死指定进程");

  345. // 6.5 获取前台 Activity(管道grep返回空,改用JS解析完整输出)
  346. print.log("\n--- 6.5 获取前台 Activity ---");
  347. // 策略1:dumpsys activity activities 完整输出 + JS搜索 mResumedActivity
  348. var activity完整6 = 执行命令("dumpsys activity activities 2>/dev/null", false);
  349. if (activity完整6 && activity完整6.length > 0) {
  350.     var resumedIdx6 = activity完整6.indexOf("mResumedActivity");
  351.     if (resumedIdx6 !== -1) {
  352.         print.log("前台Activity:" + activity完整6.substring(resumedIdx6, resumedIdx6 + 200).split("\n")[0]);
  353.     } else {
  354.         print.log("前台Activity:未找到 mResumedActivity");
  355.     }
  356. } else {
  357.     print.log("前台Activity:dumpsys activity 不可用");
  358. }
  359. // 策略2:dumpsys window 完整输出 + JS搜索 mCurrentFocus
  360. var 窗口完整6 = 执行命令("dumpsys window 2>/dev/null", false);
  361. if (窗口完整6 && 窗口完整6.length > 0) {
  362.     var focusIdx6 = 窗口完整6.indexOf("mCurrentFocus");
  363.     if (focusIdx6 !== -1) {
  364.         print.log("当前焦点窗口:" + 窗口完整6.substring(focusIdx6, focusIdx6 + 200).split("\n")[0]);
  365.     } else {
  366.         print.log("当前焦点窗口:未找到 mCurrentFocus");
  367.     }
  368. } else {
  369.     print.log("当前焦点窗口:dumpsys window 不可用");
  370. }


  371. // =============================================================================
  372. // 第七部分:文件权限与系统管理(root 场景)
  373. // =============================================================================
  374. 倒计时(3, "第七部分:root权限场景");
  375. print.log("\n========== 第七部分:root 权限场景 ==========\n");

  376. // 7.1 修改文件权限
  377. print.log("--- 7.1 修改文件权限 ---");
  378. // adb.exec("chmod 777 /data/local/tmp/test", true);  // root 权限
  379. print.log("(示例)adb.exec('chmod 777 /data/local/tmp/test', true) 以 root 修改权限");

  380. // 7.2 读取系统分区文件(需要 root)
  381. print.log("\n--- 7.2 读取系统分区文件 ---");
  382. // var hosts内容 = 执行命令("cat /etc/hosts", true);  // root 权限读取
  383. print.log("(示例)adb.exec('cat /etc/hosts', true) 以 root 读取系统文件");

  384. // 7.3 修改系统设置(settings 命令在 Android 14 非 root 下报权限错误,需 root)
  385. print.log("\n--- 7.3 修改系统设置 ---");
  386. // 获取屏幕超时时间(需 root,否则报 INTERACT_ACROSS_USERS 权限错误)
  387. var 屏幕超时 = 执行命令("settings get system screen_off_timeout", true);
  388. if (!屏幕超时 || 屏幕超时.indexOf("Exception") !== -1 || 屏幕超时.indexOf("Permission") !== -1) {
  389.     // 回退1:非root尝试
  390.     var 屏幕超时2 = 执行命令("settings get system screen_off_timeout", false);
  391.     if (屏幕超时2 && 屏幕超时2.indexOf("Exception") === -1) {
  392.         屏幕超时 = 屏幕超时2;
  393.     } else {
  394.         // 回退2:通过 content query 读取
  395.         var content查询 = 执行命令("content query --uri content://settings/system --where \"name='screen_off_timeout'\"", false);
  396.         if (content查询 && content查询.indexOf("value=") !== -1) {
  397.             var valIdx = content查询.indexOf("value=");
  398.             屏幕超时 = content查询.substring(valIdx + 6).split(",")[0].trim();
  399.         } else {
  400.             屏幕超时 = "";
  401.         }
  402.     }
  403. }
  404. print.log("当前屏幕超时:" + (屏幕超时 || "获取失败(需 root 权限)") + " 毫秒");

  405. // 修改屏幕超时(需 root)
  406. // 执行命令静默("settings put system screen_off_timeout 60000", true);
  407. print.log("(示例)settings put system screen_off_timeout 60000 → 设置屏幕超时60秒");

  408. // 7.4 获取/修改输入法(需 root)
  409. print.log("\n--- 7.4 获取/修改输入法 ---");
  410. var 当前输入法 = 执行命令("settings get secure default_input_method", true);
  411. if (!当前输入法 || 当前输入法.indexOf("Exception") !== -1 || 当前输入法.indexOf("Permission") !== -1) {
  412.     // 回退1:非root尝试
  413.     当前输入法 = 执行命令("settings get secure default_input_method", false);
  414.     if (!当前输入法 || 当前输入法.indexOf("Exception") !== -1) {
  415.         // 回退2:通过 content query 读取
  416.         var 输入法查询 = 执行命令("content query --uri content://settings/secure --where \"name='default_input_method'\"", false);
  417.         if (输入法查询 && 输入法查询.indexOf("value=") !== -1) {
  418.             var imeValIdx = 输入法查询.indexOf("value=");
  419.             当前输入法 = 输入法查询.substring(imeValIdx + 6).split(",")[0].trim();
  420.         } else {
  421.             // 回退3:通过 imba 命令(部分设备可用)
  422.             var imba列表 = 执行命令("ime list -s 2>/dev/null", false);
  423.             当前输入法 = imba列表 || "";
  424.         }
  425.     }
  426. }
  427. print.log("当前默认输入法:" + (当前输入法 || "获取失败(需 root 权限)"));

  428. // 7.5 挂载/卸载系统分区(root)
  429. print.log("\n--- 7.5 挂载系统分区读写(root)---");
  430. // adb.exec("mount -o remount,rw /system", true);
  431. print.log("(示例)adb.exec('mount -o remount,rw /system', true) 以 root 重新挂载/system为读写");

  432. // 7.6 写入系统文件(root)
  433. print.log("\n--- 7.6 写入系统 hosts 文件(root)---");
  434. // adb.exec("echo '127.0.0.1 example.com' >> /etc/hosts", true);
  435. print.log("(示例)以 root 权限修改 hosts 文件");


  436. // =============================================================================
  437. // 第八部分:网络操作
  438. // =============================================================================
  439. 倒计时(3, "第八部分:网络操作");
  440. print.log("\n========== 第八部分:网络操作 ==========\n");

  441. // 8.1 检查网络连通性
  442. print.log("--- 8.1 Ping 测试 ---");
  443. var ping结果 = 执行命令("ping -c 3 www.baidu.com", false);
  444. print.log("Ping 结果:\n" + ping结果);

  445. // 8.2 获取网络接口信息
  446. print.log("\n--- 8.2 网络接口信息 ---");
  447. var 网络接口 = 执行命令("ip addr", false);
  448. print.log("网络接口:\n" + 网络接口.substring(0, 200) + "...");

  449. // 8.3 获取路由表
  450. print.log("\n--- 8.3 路由表 ---");
  451. var 路由表 = 执行命令("ip route", false);
  452. print.log("路由表:" + 路由表);

  453. // 8.4 获取 DNS 配置(多策略:resolv.conf → getprop → dhcp属性 → dumpsys解析)
  454. print.log("\n--- 8.4 DNS 配置 ---");
  455. var DNS1 = "";
  456. var DNS2 = "";
  457. // 策略1:resolv.conf
  458. var DNS原始 = 执行命令("cat /etc/resolv.conf 2>/dev/null", false);
  459. if (DNS原始 && DNS原始.length > 0) {
  460.     var DNS行 = DNS原始.split("\n");
  461.     var DNS序号 = 0;
  462.     for (var di = 0; di < DNS行.length; di++) {
  463.         var 行 = DNS行[di].trim();
  464.         if (行.indexOf("nameserver") === 0) {
  465.             DNS序号++;
  466.             if (DNS序号 === 1) DNS1 = 行.substring("nameserver".length).trim();
  467.             else if (DNS序号 === 2) DNS2 = 行.substring("nameserver".length).trim();
  468.         }
  469.     }
  470. }
  471. // 策略2:getprop net.dns
  472. if (!DNS1) DNS1 = 执行命令("getprop net.dns1 2>/dev/null", false);
  473. if (!DNS2) DNS2 = 执行命令("getprop net.dns2 2>/dev/null", false);
  474. // 策略3:getprop dhcp.wlan0.dns(部分设备可用)
  475. if (!DNS1) DNS1 = 执行命令("getprop dhcp.wlan0.dns1 2>/dev/null", false);
  476. if (!DNS2) DNS2 = 执行命令("getprop dhcp.wlan0.dns2 2>/dev/null", false);
  477. // 策略4:解析 dumpsys connectivity(搜索 DnsServerSearchDomains 或 dns 字样)
  478. if (!DNS1) {
  479.     var 连通性完整 = 执行命令("dumpsys connectivity 2>/dev/null", false);
  480.     if (连通性完整 && 连通性完整.length > 0) {
  481.         var 连通行 = 连通性完整.split("\n");
  482.         for (var ci = 0; ci < 连通行.length; ci++) {
  483.             var 连接内容 = 连通行[ci].trim();
  484.             if (连接内容.indexOf("DnsAddresses") !== -1 || 连接内容.indexOf("dns addresses") !== -1) {
  485.                 // 尝试提取IP地址格式 x.x.x.x
  486.                 var ipMatch = 连接内容.match(/\d+\.\d+\.\d+\.\d+/g);
  487.                 if (ipMatch) {
  488.                     if (!DNS1) DNS1 = ipMatch[0];
  489.                     if (ipMatch.length > 1 && !DNS2) DNS2 = ipMatch[1];
  490.                 }
  491.             }
  492.         }
  493.     }
  494. }
  495. print.log("DNS1:" + (DNS1 || "获取失败"));
  496. print.log("DNS2:" + (DNS2 || "获取失败"));

  497. // 8.5 通过 curl 获取网络数据(部分设备支持)
  498. print.log("\n--- 8.5 curl 获取数据 ---");
  499. var curl结果 = 执行命令("curl -s http://ip-api.com/line/ 2>/dev/null", false);
  500. print.log("网络出口信息:\n" + (curl结果 || "curl 不可用或网络不通"));


  501. // =============================================================================
  502. // 第九部分:UI 自动化辅助(uiautomator)
  503. // =============================================================================
  504. 倒计时(3, "第九部分:UI自动化辅助");
  505. print.log("\n========== 第九部分:UI 自动化辅助 ==========\n");

  506. // 9.1 获取 UI XML(多策略:auto.getXml → uiautomator dump → 完整路径)
  507. print.log("--- 9.1 获取当前界面 UI XML ---");
  508. var UI_XML = "";

  509. // 策略1:优先使用 AIWROK 原生 auto.getXml()(最可靠)
  510. try {
  511.     if (typeof auto !== "undefined" && auto.getXml) {
  512.         var 原始XML = String(auto.getXml());
  513.         if (原始XML && 原始XML.length > 10 && 原始XML.indexOf("<") !== -1) {
  514.             UI_XML = 原始XML;
  515.             print.log("✓ 通过 auto.getXml() 获取成功");
  516.         }
  517.     }
  518. } catch (e1) {
  519.     print.log("⚠ auto.getXml() 失败: " + e1.message);
  520. }

  521. // 策略2:uiautomator dump(如果 auto.getXml 不可用)
  522. if (!UI_XML) {
  523.     执行命令静默("mkdir -p /sdcard/aiwrok_test", false);
  524.     var UI临时文件 = "/sdcard/aiwrok_test/ui_dump.xml";
  525.     // 先尝试 --compressed
  526.     var dump结果1 = 执行命令("uiautomator dump --compressed " + UI临时文件 + " 2>&1", false);
  527.     sleep.millisecond(500);
  528.     UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
  529.     if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
  530.         print.log("✓ 通过 uiautomator --compressed 获取成功");
  531.     } else {
  532.         // 回退:不带 --compressed
  533.         var dump结果2 = 执行命令("uiautomator dump " + UI临时文件 + " 2>&1", false);
  534.         sleep.millisecond(500);
  535.         UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
  536.         if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
  537.             print.log("✓ 通过 uiautomator dump 获取成功(非压缩模式)");
  538.         } else {
  539.             // 回退:尝试 /system/bin/ 完整路径
  540.             var dump结果3 = 执行命令("/system/bin/uiautomator dump " + UI临时文件 + " 2>&1", false);
  541.             sleep.millisecond(500);
  542.             UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
  543.             if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
  544.                 print.log("✓ 通过 /system/bin/uiautomator 获取成功");
  545.             } else {
  546.                 UI_XML = "";
  547.             }
  548.         }
  549.     }
  550. }

  551. if (UI_XML && UI_XML.length > 10) {
  552.     print.log("UI XML 长度:" + UI_XML.length + " 字符");
  553.     print.log("UI XML 前200字符:" + UI_XML.substring(0, 200) + "...");
  554. } else {
  555.     print.log("⚠ 获取 UI XML 失败(uiautomator 不可用且 auto.getXml 不可用)");
  556. }

  557. // 9.2 获取当前界面包名(多策略:dumpsys window → dumpsys activity → AIWROK原生 → shell)
  558. print.log("\n--- 9.2 获取当前界面包名 ---");
  559. var 前台包名 = "";
  560. var 前台Activity = "";
  561. var activity完整 = "";

  562. // 策略1:dumpsys window 完整输出 + JS搜索 mCurrentFocus
  563. var 窗口完整 = 执行命令("dumpsys window 2>/dev/null", false);
  564. if (窗口完整 && 窗口完整.length > 0) {
  565.     var focusIndex = 窗口完整.indexOf("mCurrentFocus");
  566.     if (focusIndex !== -1) {
  567.         var focusLine = 窗口完整.substring(focusIndex, focusIndex + 200).split("\n")[0];
  568.         print.log("焦点窗口:" + focusLine);
  569.         var spaceIdx = focusLine.indexOf(" ");
  570.         if (spaceIdx !== -1) {
  571.             var sub = focusLine.substring(spaceIdx + 1);
  572.             var slashIdx = sub.indexOf("/");
  573.             if (slashIdx !== -1) {
  574.                 前台包名 = sub.substring(0, slashIdx);
  575.                 print.log("当前前台包名:" + 前台包名);
  576.             }
  577.         }
  578.     } else {
  579.         // 回退:搜索 mFocusedApp
  580.         var appIndex = 窗口完整.indexOf("mFocusedApp");
  581.         if (appIndex !== -1) {
  582.             var appLine = 窗口完整.substring(appIndex, appIndex + 200).split("\n")[0];
  583.             print.log("焦点应用:" + appLine);
  584.             var appSlash = appLine.indexOf("/");
  585.             if (appSlash !== -1) {
  586.                 var appSub = appLine.substring(appLine.indexOf(" ") + 1, appSlash);
  587.                 if (appSub) 前台包名 = appSub;
  588.             }
  589.         }
  590.     }
  591. }

  592. // 策略2:dumpsys activity activities + JS搜索 mResumedActivity
  593. if (!前台包名) {
  594.     activity完整 = 执行命令("dumpsys activity activities 2>/dev/null", false);
  595.     if (activity完整 && activity完整.length > 0) {
  596.         var resumedIdx = activity完整.indexOf("mResumedActivity");
  597.         if (resumedIdx !== -1) {
  598.             var resumedLine = activity完整.substring(resumedIdx, resumedIdx + 300).split("\n")[0];
  599.             print.log("前台Activity:" + resumedLine);
  600.             // 提取包名:格式通常为 mResumedActivity: ActivityRecord{... u0 com.xxx.xxx/...}
  601.             var 包名提取 = resumedLine.match(/(\w+\.\w+\.\w+)/);
  602.             if (包名提取) {
  603.                 前台包名 = 包名提取[1];
  604.                 print.log("当前前台包名(从Activity提取):" + 前台包名);
  605.             }
  606.         }
  607.     }
  608. }

  609. // 策略3:AIWROK 原生方法(部分方法不稳定,作为最后回退)
  610. if (!前台包名) {
  611.     try {
  612.         if (typeof auto !== "undefined") {
  613.             if (auto.getTopPackName) 前台包名 = String(auto.getTopPackName());
  614.             if (!前台包名 && auto.getTopPackNameV2) 前台包名 = String(auto.getTopPackNameV2());
  615.             if (!前台包名 && auto.getPackName) 前台包名 = String(auto.getPackName());
  616.         }
  617.     } catch (e3) {
  618.         print.log("⚠ AIWROK 原生方法获取包名失败: " + e3.message);
  619.     }
  620. }

  621. if (!前台包名) {
  622.     print.log("⚠ 未获取到前台包名(dumpsys 和 AIWROK 方法均不可用)");
  623. }

  624. // 9.3 获取 Activity 栈
  625. print.log("\n--- 9.3 获取 Activity 栈信息 ---");
  626. // 确保 activity完整 有值(可能在 9.2 策略2 中已获取)
  627. if (!activity完整) {
  628.     activity完整 = 执行命令("dumpsys activity activities 2>/dev/null", false);
  629. }
  630. if (activity完整 && activity完整.length > 0) {
  631.     // 在 JS 中搜索关键字
  632.     var 栈行 = activity完整.split("\n");
  633.     var 栈输出 = [];
  634.     for (var si = 0; si < 栈行.length; si++) {
  635.         if (栈行[si].indexOf("Run #") !== -1 || 栈行[si].indexOf("mResumed") !== -1) {
  636.             栈输出.push(栈行[si].trim());
  637.         }
  638.     }
  639.     if (栈输出.length > 0) {
  640.         for (var sj = 0; sj < 栈输出.length; sj++) {
  641.             print.log("  " + 栈输出[sj]);
  642.         }
  643.     } else {
  644.         // 回退:输出前5行看看格式
  645.         print.log("Activity栈:未找到 Run # 信息,输出前5行:");
  646.         for (var sk = 0; sk < Math.min(5, 栈行.length); sk++) {
  647.             print.log("  " + 栈行[sk].trim());
  648.         }
  649.     }
  650. } else {
  651.     print.log("Activity栈:dumpsys activity 不可用");
  652. }


  653. // =============================================================================
  654. // 第十部分:综合实战 —— 应用信息采集器
  655. // =============================================================================
  656. 倒计时(3, "第十部分:应用信息采集器");
  657. print.log("\n========== 第十部分:综合实战:应用信息采集器 ==========\n");

  658. /**
  659. * 综合示例:采集设备上所有第三方应用的详细信息
  660. * 展示 adb.exec 在复杂场景下的组合使用
  661. */

  662. // 工具函数:获取指定包名的应用详细信息
  663. function 获取应用详情(包名) {
  664.     var 详情 = {
  665.         包名: 包名,
  666.         版本名: "",
  667.         版本号: "",
  668.         安装路径: "",
  669.         数据目录: "",
  670.         大小: "",
  671.         是否运行: false
  672.     };

  673.     try {
  674.         // 获取完整 package 信息(dumpsys 管道在部分设备返回空,改用 JS 解析)
  675.         var 包信息完整 = 执行命令("dumpsys package " + 包名 + " 2>/dev/null", false);
  676.         if (包信息完整 && 包信息完整.length > 0) {
  677.             // 策略1:搜索 versionName= (标准格式)
  678.             var vNameIdx = 包信息完整.indexOf("versionName=");
  679.             if (vNameIdx !== -1) {
  680.                 var vNameSub = 包信息完整.substring(vNameIdx + "versionName=".length);
  681.                 详情.版本名 = vNameSub.split("\n")[0].trim();
  682.             }
  683.             // 策略2:搜索 versionName (不带=,部分MIUI/HyperOS格式)
  684.             if (!详情.版本名) {
  685.                 var vNameIdx2 = 包信息完整.indexOf("versionName ");
  686.                 if (vNameIdx2 !== -1) {
  687.                     var vNameSub2 = 包信息完整.substring(vNameIdx2 + "versionName ".length);
  688.                     详情.版本名 = vNameSub2.split("\n")[0].trim();
  689.                 }
  690.             }
  691.             // 搜索 versionCode
  692.             var vCodeIdx = 包信息完整.indexOf("versionCode=");
  693.             if (vCodeIdx !== -1) {
  694.                 var vCodeSub = 包信息完整.substring(vCodeIdx + "versionCode=".length);
  695.                 详情.版本号 = vCodeSub.split(" ")[0].trim();
  696.             }
  697.             if (!详情.版本号) {
  698.                 var vCodeIdx2 = 包信息完整.indexOf("versionCode ");
  699.                 if (vCodeIdx2 !== -1) {
  700.                     var vCodeSub2 = 包信息完整.substring(vCodeIdx2 + "versionCode ".length);
  701.                     详情.版本号 = vCodeSub2.split(" ")[0].trim();
  702.                 }
  703.             }
  704.         }

  705.         // 策略3:如果 dumpsys package 未找到,尝试 pm dump
  706.         if (!详情.版本名) {
  707.             var pmDump = 执行命令("pm dump " + 包名 + " 2>/dev/null", false);
  708.             if (pmDump && pmDump.length > 0) {
  709.                 var pmVNameIdx = pmDump.indexOf("versionName=");
  710.                 if (pmVNameIdx !== -1) {
  711.                     详情.版本名 = pmDump.substring(pmVNameIdx + "versionName=".length).split("\n")[0].trim();
  712.                 }
  713.                 var pmVCodeIdx = pmDump.indexOf("versionCode=");
  714.                 if (pmVCodeIdx !== -1) {
  715.                     详情.版本号 = pmDump.substring(pmVCodeIdx + "versionCode=".length).split(" ")[0].trim();
  716.                 }
  717.             }
  718.         }

  719.         // 获取安装路径
  720.         var 路径信息 = 执行命令("pm path " + 包名, false);
  721.         if (路径信息) {
  722.             详情.安装路径 = 路径信息.replace("package:", "").trim();
  723.         }

  724.         // 检查是否正在运行
  725.         var 进程检查 = 执行命令("ps | grep " + 包名, false);
  726.         详情.是否运行 = !!(进程检查 && 进程检查.length > 0);

  727.     } catch (e) {
  728.         print.log("⚠ 获取 " + 包名 + " 详情失败: " + e.message);
  729.     }

  730.     return 详情;
  731. }

  732. // 工具函数:获取设备综合信息
  733. function 获取设备信息() {
  734.     var 设备 = {};
  735.     try {
  736.         设备.型号 = 执行命令("getprop ro.product.model", false);
  737.         设备.品牌 = 执行命令("getprop ro.product.brand", false);
  738.         设备.安卓版本 = 执行命令("getprop ro.build.version.release", false);
  739.         设备.SDK = 执行命令("getprop ro.build.version.sdk", false);
  740.         设备.分辨率 = 执行命令("wm size", false);
  741.         // 电池信息改用多策略获取函数
  742.         var 设备电池 = 获取电池信息();
  743.         设备.电量 = 设备电池.电量 ? (设备电池.电量 + "%") : "未知";
  744.         设备.总内存 = 执行命令("cat /proc/meminfo | head -1", false);
  745.         设备.可用存储 = 执行命令("df /sdcard | tail -1", false);
  746.     } catch (e) {
  747.         print.log("⚠ 获取设备信息失败: " + e.message);
  748.     }
  749.     return 设备;
  750. }

  751. // 执行采集
  752. print.log("--- 10.1 采集设备信息 ---");
  753. var 设备信息 = 获取设备信息();
  754. print.log("设备型号:" + 设备信息.型号);
  755. print.log("设备品牌:" + 设备信息.品牌);
  756. print.log("安卓版本:" + 设备信息.安卓版本);
  757. print.log("屏幕分辨率:" + 设备信息.分辨率);
  758. print.log("电量信息:" + 设备信息.电量);
  759. print.log("内存信息:" + 设备信息.总内存);

  760. print.log("\n--- 10.2 采集第三方应用信息(前3个)---");
  761. var 应用列表原始 = 执行命令("pm list packages -3", false);
  762. if (应用列表原始) {
  763.     var 应用列表 = 应用列表原始.split("\n");
  764.     var 采集数量 = Math.min(3, 应用列表.length);
  765.     for (var j = 0; j < 采集数量; j++) {
  766.         var 包名 = 应用列表[j].replace("package:", "").trim();
  767.         if (包名) {
  768.             print.log("\n  应用 " + (j + 1) + ": " + 包名);
  769.             var 详情 = 获取应用详情(包名);
  770.             print.log("    版本名: " + 详情.版本名);
  771.             print.log("    版本号: " + 详情.版本号);
  772.             print.log("    安装路径: " + 详情.安装路径);
  773.             print.log("    是否运行: " + (详情.是否运行 ? "是 ✓" : "否"));
  774.         }
  775.     }
  776. }


  777. // =============================================================================
  778. // 第十一部分:综合实战 —— 系统监控工具
  779. // =============================================================================
  780. 倒计时(3, "第十一部分:系统监控工具");
  781. print.log("\n\n========== 第十一部分:综合实战:系统监控工具 ==========\n");

  782. /**
  783. * 综合示例:系统资源监控工具
  784. * 定时采集 CPU、内存、电池、网络等系统指标
  785. */

  786. // 工具函数:获取 CPU 使用率(top 命令输出格式因设备而异,多策略解析)
  787. function 获取CPU使用率() {
  788.     try {
  789.         var cpu信息 = 执行命令("top -n 1 -b 2>/dev/null", false);
  790.         if (cpu信息) {
  791.             var 行数组 = cpu信息.split("\n");
  792.             for (var k = 0; k < 行数组.length; k++) {
  793.                 var 行 = 行数组[k].trim();
  794.                 // 匹配包含 CPU 和 % 的行(如 "400%cpu 12%user 4%nice 8%sys 376%idle")
  795.                 if (行.indexOf("cpu") !== -1 && 行.indexOf("%") !== -1 && 行.indexOf("PID") === -1) {
  796.                     return 行;
  797.                 }
  798.             }
  799.             // 如果没找到 CPU 行,返回前3行
  800.             return 行数组.slice(0, 3).join("\n");
  801.         }
  802.     } catch (e) {
  803.         print.log("⚠ 获取CPU使用率失败: " + e.message);
  804.     }
  805.     return "获取失败";
  806. }

  807. // 工具函数:获取内存使用情况
  808. function 获取内存使用() {
  809.     try {
  810.         var meminfo = 执行命令("cat /proc/meminfo | head -3", false);
  811.         return meminfo || "获取失败";
  812.     } catch (e) {
  813.         return "获取失败: " + e.message;
  814.     }
  815. }

  816. // 工具函数:获取电池详细信息(多策略:sysfs文件 → dumpsys解析 → getprop回退)
  817. function 获取电池信息() {
  818.     var 电池 = { 电量: "", 温度: "", 状态: "", 技术: "" };
  819.     try {
  820.         // 策略1:sysfs 文件系统(标准路径)
  821.         电池.电量 = 执行命令("cat /sys/class/power_supply/battery/capacity 2>/dev/null", false);
  822.         var 温度原始 = 执行命令("cat /sys/class/power_supply/battery/temp 2>/dev/null", false);
  823.         if (温度原始) {
  824.             var 温度值 = parseInt(温度原始.trim(), 10);
  825.             电池.温度 = isNaN(温度值) ? "" : (温度值 / 10) + "°C";
  826.         }
  827.         var 状态原始 = 执行命令("cat /sys/class/power_supply/battery/status 2>/dev/null", false);
  828.         var 状态映射 = {"Charging": "充电中", "Discharging": "放电中", "Full": "已充满", "Not charging": "未充电"};
  829.         电池.状态 = 状态映射[状态原始] || 状态原始 || "";
  830.         电池.技术 = 执行命令("cat /sys/class/power_supply/battery/technology 2>/dev/null", false);

  831.         // 策略2:如果 sysfs 为空,用 dumpsys battery 解析(不用管道grep,直接JS搜索)
  832.         if (!电池.电量) {
  833.             var dumpsys电池 = 执行命令("dumpsys battery 2>/dev/null", false);
  834.             if (dumpsys电池 && dumpsys电池.length > 0) {
  835.                 var 电池行 = dumpsys电池.split("\n");
  836.                 for (var bi = 0; bi < 电池行.length; bi++) {
  837.                     var 行内容 = 电池行[bi].trim();
  838.                     if (行内容.indexOf("level:") !== -1 && !电池.电量) {
  839.                         电池.电量 = 行内容.replace("level:", "").trim();
  840.                     }
  841.                     if (行内容.indexOf("temperature:") !== -1 && !电池.温度) {
  842.                         var 温度提取 = parseInt(行内容.replace("temperature:", "").trim(), 10);
  843.                         电池.温度 = isNaN(温度提取) ? "" : (温度提取 / 10) + "°C";
  844.                     }
  845.                     if (行内容.indexOf("status:") !== -1 && !电池.状态) {
  846.                         var 状态提取 = 行内容.replace("status:", "").trim();
  847.                         电池.状态 = 状态映射[状态提取] || 状态提取 || "";
  848.                     }
  849.                     if (行内容.indexOf("technology:") !== -1 && !电池.技术) {
  850.                         电池.技术 = 行内容.replace("technology:", "").trim();
  851.                     }
  852.                 }
  853.             }
  854.         }

  855.         // 策略3:如果仍为空,尝试 bms 路径(部分高通设备)
  856.         if (!电池.电量) {
  857.             电池.电量 = 执行命令("cat /sys/class/power_supply/bms/capacity 2>/dev/null", false);
  858.         }
  859.     } catch (e) {
  860.         print.log("⚠ 获取电池信息失败: " + e.message);
  861.     }
  862.     return 电池;
  863. }

  864. // 工具函数:获取网络流量统计
  865. function 获取网络流量() {
  866.     try {
  867.         // 获取 wlan0 接口的流量统计
  868.         var 流量 = 执行命令("cat /proc/net/dev | grep wlan0", false);
  869.         if (流量) {
  870.             // /proc/net/dev 格式: "  wlan0: rx_bytes rx_packets ... tx_bytes tx_packets ..."
  871.             // trim 后 split: 字段[0]="wlan0:" 字段[1]=rx_bytes 字段[2]=rx_packets ... 字段[9]=tx_bytes 字段[10]=tx_packets
  872.             var 字段 = 流量.trim().split(/\s+/);
  873.             if (字段.length >= 11) {
  874.                 return {
  875.                     接收字节: 字段[1],
  876.                     接收包数: 字段[2],
  877.                     发送字节: 字段[9],
  878.                     发送包数: 字段[10]
  879.                 };
  880.             }
  881.         }
  882.     } catch (e) {
  883.         print.log("⚠ 获取网络流量失败: " + e.message);
  884.     }
  885.     return null;
  886. }

  887. // 执行监控
  888. print.log("--- 11.1 系统资源快照 ---");
  889. print.log("\n[CPU 使用率]");
  890. print.log("  " + 获取CPU使用率());

  891. print.log("\n[内存使用]");
  892. var 内存 = 获取内存使用();
  893. var 内存行 = 内存.split("\n");
  894. for (var p = 0; p < 内存行.length; p++) {
  895.     print.log("  " + 内存行[p]);
  896. }

  897. print.log("\n[电池信息]");
  898. var 电池 = 获取电池信息();
  899. print.log("  电量: " + (电池.电量 || "未知") + "%");
  900. print.log("  温度: " + (电池.温度 || "未知"));
  901. print.log("  状态: " + (电池.状态 || "未知"));
  902. print.log("  电池技术: " + (电池.技术 || "未知"));

  903. print.log("\n[网络流量]");
  904. var 流量 = 获取网络流量();
  905. if (流量) {
  906.     print.log("  接收: " + 流量.接收字节 + " 字节 / " + 流量.接收包数 + " 包");
  907.     print.log("  发送: " + 流量.发送字节 + " 字节 / " + 流量.发送包数 + " 包");
  908. } else {
  909.     print.log("  获取流量信息失败");
  910. }


  911. // =============================================================================
  912. // 第十二部分:综合实战 —— 智能清理工具
  913. // =============================================================================
  914. 倒计时(3, "第十二部分:智能清理工具");
  915. print.log("\n\n========== 第十二部分:综合实战:智能清理工具 ==========\n");

  916. /**
  917. * 综合示例:智能清理工具
  918. * 清理缓存、杀死后台进程、释放内存
  919. * 展示 root 和非 root 模式的组合使用
  920. */

  921. // 工具函数:获取缓存大小
  922. function 获取缓存大小() {
  923.     try {
  924.         var 缓存信息 = 执行命令("du -sh /sdcard/Android/data/*/cache 2>/dev/null", false);
  925.         return 缓存信息 || "无缓存数据";
  926.     } catch (e) {
  927.         return "获取失败";
  928.     }
  929. }

  930. // 工具函数:清理指定应用的缓存
  931. function 清理应用缓存(包名) {
  932.     // pm clear 会清除所有数据(包括登录状态),谨慎使用
  933.     // 这里使用 root 权限只清缓存目录
  934.     var 结果 = 执行命令("rm -rf /sdcard/Android/data/" + 包名 + "/cache/* 2>/dev/null", false);
  935.     return 结果;
  936. }

  937. // 工具函数:强制停止所有第三方后台应用
  938. function 停止后台应用() {
  939.     var 停止数量 = 0;
  940.     try {
  941.         var 应用列表 = 执行命令("pm list packages -3", false);
  942.         if (应用列表) {
  943.             var 应用 = 应用列表.split("\n");
  944.             for (var q = 0; q < 应用.length; q++) {
  945.                 var 包名 = 应用[q].replace("package:", "").trim();
  946.                 if (包名) {
  947.                     // 检查是否在运行
  948.                     var 进程 = 执行命令("ps | grep " + 包名, false);
  949.                     if (进程 && 进程.length > 0) {
  950.                         // 强制停止
  951.                         执行命令静默("am force-stop " + 包名, false);
  952.                         print.log("  ✓ 已停止: " + 包名);
  953.                         停止数量++;
  954.                     }
  955.                 }
  956.             }
  957.         }
  958.     } catch (e) {
  959.         print.log("⚠ 停止后台应用失败: " + e.message);
  960.     }
  961.     return 停止数量;
  962. }

  963. // 执行清理(演示模式,不实际执行)
  964. print.log("--- 12.1 查看缓存情况 ---");
  965. print.log("缓存信息:\n" + 获取缓存大小());

  966. print.log("\n--- 12.2 清理临时文件 ---");
  967. 执行命令静默("rm -rf /sdcard/aiwrok_test/* 2>/dev/null", false);
  968. print.log("✓ 已清理 /sdcard/aiwrok_test/ 临时文件");

  969. print.log("\n--- 12.3 停止后台应用(需要时启用)---");
  970. print.log("(演示模式)实际使用时调用 停止后台应用() 函数");

  971. // 使用 root 模式清空系统缓存(高级操作)
  972. print.log("\n--- 12.4 系统级缓存清理(root)---");
  973. // adb.exec("echo 3 > /proc/sys/vm/drop_caches", true);  // root 权限释放内存
  974. print.log("(示例)adb.exec('echo 3 > /proc/sys/vm/drop_caches', true) 以 root 清空系统缓存");


  975. // =============================================================================
  976. // 第十三部分:adb.exec 与 agent.shell 对比与互转
  977. // =============================================================================
  978. 倒计时(3, "第十三部分:API对比与互转");
  979. print.log("\n\n========== 第十三部分:adb.exec 与 agent.shell 对比 ==========\n");

  980. print.log("┌─────────────┬────────────────────┬────────────────────┐");
  981. print.log("│   特性      │   adb.exec()       │   agent.shell()    │");
  982. print.log("├─────────────┼────────────────────┼────────────────────┤");
  983. print.log("│ 权限控制    │ 第二参数控制 root  │ 需要代理模式/root  │");
  984. print.log("│ 返回值      │ 需清洗 successMsg  │ 相对干净           │");
  985. print.log("│ 适用场景    │ 通用命令执行       │ 代理模式自动化     │");
  986. print.log("│ root 支持   │ isRoot=true 即可   │ 依赖代理模式       │");
  987. print.log("│ 异常处理    │ 需 try-catch       │ 需 try-catch       │");
  988. print.log("│ 执行模式    │ 设备端直接执行     │ 通过 agent 代理    │");
  989. print.log("└─────────────┴────────────────────┴────────────────────┘");

  990. // 互转示例:统一命令执行接口
  991. print.log("\n--- 统一命令执行接口(自动选择 adb.exec 或 agent.shell)---");

  992. function 智能执行(命令, 需要root) {
  993.     var 结果 = "";
  994.     try {
  995.         // 优先使用 adb.exec
  996.         if (typeof adb !== "undefined" && adb.exec) {
  997.             var 原始 = adb.exec(命令, 需要root || false);
  998.             结果 = 清洗输出(String(原始));
  999.             print.log("[adb.exec] " + 命令 + " → " + 结果.substring(0, 50));
  1000.         }
  1001.         // 回退到 agent.shell
  1002.         else if (typeof agent !== "undefined" && agent.shell) {
  1003.             结果 = String(agent.shell(命令));
  1004.             print.log("[agent.shell] " + 命令 + " → " + 结果.substring(0, 50));
  1005.         }
  1006.         // 回退到 shell.exec
  1007.         else if (typeof shell !== "undefined" && shell.exec) {
  1008.             结果 = String(shell.exec(命令));
  1009.             print.log("[shell.exec] " + 命令 + " → " + 结果.substring(0, 50));
  1010.         }
  1011.         else {
  1012.             print.log("⚠ 无可用的命令执行接口");
  1013.         }
  1014.     } catch (e) {
  1015.         print.log("⚠ 智能执行异常: " + e.message);
  1016.     }
  1017.     return 结果;
  1018. }

  1019. // 测试统一接口
  1020. print.log("\n测试统一接口:");
  1021. 智能执行("getprop ro.product.model", false);
  1022. 智能执行("ls /sdcard/", false);


  1023. // =============================================================================
  1024. // 第十四部分:定时任务 —— 周期性系统监控
  1025. // =============================================================================
  1026. 倒计时(3, "第十四部分:定时系统监控");
  1027. print.log("\n\n========== 第十四部分:定时系统监控 ==========\n");

  1028. /**
  1029. * 综合示例:定时监控系统状态并记录日志
  1030. * 使用 setInterval 周期性采集系统信息
  1031. */

  1032. var 监控次数 = 0;
  1033. var 最大监控次数 = 3;  // 演示用,实际可设为更大值

  1034. function 系统监控任务() {
  1035.     监控次数++;
  1036.     print.log("\n--- 第 " + 监控次数 + " 次监控 [" + new Date().toLocaleTimeString() + "] ---");

  1037.     // 采集 CPU
  1038.     var cpu = 获取CPU使用率();
  1039.     print.log("  CPU: " + cpu);

  1040.     // 采集内存
  1041.     var mem = 执行命令("cat /proc/meminfo | head -1", false);
  1042.     print.log("  内存: " + mem);

  1043.     // 采集电池
  1044.     var 电池 = 获取电池信息();
  1045.     print.log("  电量: " + (电池.电量 || "?") + "% | 温度: " + (电池.温度 || "?"));

  1046.     // 采集前台应用(管道grep返回空,改用JS解析dumpsys window完整输出)
  1047.     var 监控窗口 = 执行命令("dumpsys window 2>/dev/null", false);
  1048.     if (监控窗口 && 监控窗口.length > 0) {
  1049.         var focusIdx = 监控窗口.indexOf("mCurrentFocus");
  1050.         if (focusIdx !== -1) {
  1051.             var focus行 = 监控窗口.substring(focusIdx, focusIdx + 200).split("\n")[0];
  1052.             print.log("  前台: " + focus行);
  1053.         } else {
  1054.             // 回退:搜索 mFocusedApp
  1055.             var appIdx = 监控窗口.indexOf("mFocusedApp");
  1056.             if (appIdx !== -1) {
  1057.                 var app行 = 监控窗口.substring(appIdx, appIdx + 200).split("\n")[0];
  1058.                 print.log("  前台: " + app行);
  1059.             } else {
  1060.                 print.log("  前台: 未获取到焦点窗口");
  1061.             }
  1062.         }
  1063.     } else {
  1064.         print.log("  前台: dumpsys window 不可用");
  1065.     }

  1066.     if (监控次数 >= 最大监控次数) {
  1067.         print.log("\n✓ 监控完成,共执行 " + 监控次数 + " 次");
  1068.     }
  1069. }

  1070. // 执行一次监控演示
  1071. 系统监控任务();

  1072. // 实际定时监控(取消注释即可启用)
  1073. // setInterval(function() {
  1074. //     系统监控任务();
  1075. // }, 60000);  // 每60秒监控一次


  1076. // =============================================================================
  1077. // 第十五部分:日志记录系统
  1078. // =============================================================================
  1079. 倒计时(3, "第十五部分:日志记录系统");
  1080. print.log("\n\n========== 第十五部分:adb.exec 日志记录系统 ==========\n");

  1081. /**
  1082. * 综合示例:将 adb.exec 执行结果写入日志文件
  1083. * 实现命令执行日志的持久化存储
  1084. */

  1085. function 写入日志(内容) {
  1086.     var 时间戳 = new Date().toISOString();
  1087.     var 日志行 = "[" + 时间戳 + "] " + 内容 + "\n";
  1088.     // 使用 echo 追加写入日志文件
  1089.     执行命令静默("echo '" + 日志行.replace(/'/g, "'\\''") + "' >> /sdcard/aiwrok_test/adb_log.txt", false);
  1090. }

  1091. function 记录命令执行(命令, 是否root) {
  1092.     var 开始时间 = Date.now();
  1093.     var 结果 = 执行命令(命令, 是否root);
  1094.     var 耗时 = Date.now() - 开始时间;

  1095.     var 日志内容 = "CMD: " + 命令 + " | ROOT: " + 是否root + " | TIME: " + 耗时 + "ms | RESULT: " + 结果.substring(0, 100);
  1096.     写入日志(日志内容);
  1097.     print.log("  &#128221; " + 日志内容);

  1098.     return 结果;
  1099. }

  1100. print.log("--- 15.1 记录命令执行日志 ---");
  1101. // 创建日志目录
  1102. 执行命令静默("mkdir -p /sdcard/aiwrok_test", false);
  1103. // 执行并记录
  1104. 记录命令执行("getprop ro.product.model", false);
  1105. 记录命令执行("ls /sdcard/", false);
  1106. // 电池信息:不用 grep 管道(返回空),改用多策略获取函数
  1107. var 电池日志 = 获取电池信息();
  1108. 记录命令执行("echo 'battery_level=" + (电池日志.电量 || "unknown") + " temp=" + (电池日志.温度 || "unknown") + "'", false);

  1109. print.log("\n--- 15.2 查看日志文件 ---");
  1110. var 日志内容 = 执行命令("cat /sdcard/aiwrok_test/adb_log.txt 2>/dev/null", false);
  1111. print.log("日志内容:\n" + (日志内容 || "日志为空"));


  1112. // =============================================================================
  1113. // 总结
  1114. // =============================================================================
  1115. print.log("\n\n========== 总结 ==========\n");
  1116. print.log("adb.exec(command, isRoot) 核心用法:");
  1117. print.log("  1. 基础用法:adb.exec('ls', false) → 非root执行ls命令");
  1118. print.log("  2. root用法:adb.exec('chmod 777 /data/tmp', true) → root执行");
  1119. print.log("  3. 文件操作:ls/cat/cp/mv/rm/mkdir/chmod");
  1120. print.log("  4. 应用管理:pm list/install/uninstall/clear, am start/force-stop");
  1121. print.log("  5. 系统信息:getprop/dumpsys/wm size/df/cat /proc/meminfo");
  1122. print.log("  6. 输入模拟:input tap/swipe/text/keyevent");
  1123. print.log("  7. 截图录屏:screencap/screenrecord");
  1124. print.log("  8. 进程管理:ps/top/kill");
  1125. print.log("  9. 网络操作:ping/ip/curl");
  1126. print.log(" 10. UI辅助:uiautomator dump");
  1127. print.log("");
  1128. print.log("注意事项:");
  1129. print.log("  - 返回值为 JSON 格式 {\"errorMsg\":\"\",\"success\":\"内容\"},需提取 success 字段");
  1130. print.log("  - Java String 需用 String() 转为 JS 原生字符串再做正则/分割");
  1131. print.log("  - 不支持 grep -P,使用普通 grep");
  1132. print.log("  - root 模式需设备已 root 或 PC_ADB 连接");
  1133. print.log("  - 建议所有调用包裹 try-catch 防止异常");
  1134. print.log("  - isRoot=true 时底层通过 su -c 执行,需 root 权限");

  1135. print.log("\n✅ adb.exec() 高级用法示例执行完毕");
复制代码



unto京东每日签到领京豆脚本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三大主流论坛,有手机验证码收件,邮件收发的功能,支持验证码识别,注册问题识别,多线程任务,自动上传头像,自动激活注册邮件,兼容防注册插件,本站软件原创正版,更新效率最快的原创软件。 『网络推广软件』『自动发帖软件』『 自动发帖