YYPOST群发软件 发表于 7 天前

adb.exec() 高级用法完整示例

adb.exec() 高级用法完整示例


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

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

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

    // 格式1: JSON 格式 {"errorMsg":"","success":"实际内容"}
    if (结果.charAt(0) === "{") {
      try {
            var json = JSON.parse(结果);
            if (json && json.success !== undefined) {
                // 检查是否有错误
                if (json.errorMsg && json.errorMsg !== "") {
                  print.log("⚠ 命令返回错误: " + json.errorMsg);
                }
                return String(json.success).trim();
            }
      } catch (e) {
            // JSON.parse 失败,尝试正则提取 success 字段
            var successMatch = 结果.match(/"success"\s*:\s*"([\s\S]*?)"\s*[,}]/);
            if (successMatch) {
                return successMatch
                  .replace(/\\n/g, "\n")
                  .replace(/\\t/g, "\t")
                  .replace(/\\"/g, '"')
                  .replace(/\\\\/g, "\\")
                  .trim();
            }
      }
      return 结果.trim();
    }

    // 格式2: 旧格式 successMsg:内容,errorMsg:内容(兼容 agent.shell)
    if (结果.indexOf("successMsg:") === 0) {
      结果 = 结果.substring("successMsg:".length);
    }
    var 错误索引 = 结果.indexOf(",errorMsg:");
    if (错误索引 !== -1) {
      结果 = 结果.substring(0, 错误索引);
    }
    return 结果.trim();
}

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

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

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


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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

// 3.7 获取网络连接信息
print.log("\n--- 3.7 获取网络信息 ---");
var IP地址 = 执行命令("ip addr show wlan0 | grep 'inet '", false);
print.log("IP地址:" + IP地址);
// WiFi状态:管道grep返回空,改用JS解析 dumpsys wifi 完整输出
var WiFi完整 = 执行命令("dumpsys wifi 2>/dev/null", false);
var WiFi状态 = "未知";
if (WiFi完整 && WiFi完整.length > 0) {
    var WiFi行 = WiFi完整.split("\n");
    for (var wi = 0; wi < WiFi行.length; wi++) {
      var 行内容 = WiFi行.trim().toLowerCase();
      if (行内容.indexOf("wi-fi is") !== -1 || 行内容.indexOf("wifi is") !== -1) {
            WiFi状态 = WiFi行.trim();
            break;
      }
    }
    // 回退:搜索 "Wi-Fi" 关键字所在行
    if (WiFi状态 === "未知") {
      for (var wi2 = 0; wi2 < WiFi行.length; wi2++) {
            if (WiFi行.toLowerCase().indexOf("wifi") !== -1 && WiFi行.indexOf("SSID") !== -1) {
                WiFi状态 = WiFi行.trim();
                break;
            }
      }
    }
}
print.log("WiFi状态:" + WiFi状态);


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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

// 6.5 获取前台 Activity(管道grep返回空,改用JS解析完整输出)
print.log("\n--- 6.5 获取前台 Activity ---");
// 策略1:dumpsys activity activities 完整输出 + JS搜索 mResumedActivity
var activity完整6 = 执行命令("dumpsys activity activities 2>/dev/null", false);
if (activity完整6 && activity完整6.length > 0) {
    var resumedIdx6 = activity完整6.indexOf("mResumedActivity");
    if (resumedIdx6 !== -1) {
      print.log("前台Activity:" + activity完整6.substring(resumedIdx6, resumedIdx6 + 200).split("\n"));
    } else {
      print.log("前台Activity:未找到 mResumedActivity");
    }
} else {
    print.log("前台Activity:dumpsys activity 不可用");
}
// 策略2:dumpsys window 完整输出 + JS搜索 mCurrentFocus
var 窗口完整6 = 执行命令("dumpsys window 2>/dev/null", false);
if (窗口完整6 && 窗口完整6.length > 0) {
    var focusIdx6 = 窗口完整6.indexOf("mCurrentFocus");
    if (focusIdx6 !== -1) {
      print.log("当前焦点窗口:" + 窗口完整6.substring(focusIdx6, focusIdx6 + 200).split("\n"));
    } else {
      print.log("当前焦点窗口:未找到 mCurrentFocus");
    }
} else {
    print.log("当前焦点窗口:dumpsys window 不可用");
}


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

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

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

// 7.3 修改系统设置(settings 命令在 Android 14 非 root 下报权限错误,需 root)
print.log("\n--- 7.3 修改系统设置 ---");
// 获取屏幕超时时间(需 root,否则报 INTERACT_ACROSS_USERS 权限错误)
var 屏幕超时 = 执行命令("settings get system screen_off_timeout", true);
if (!屏幕超时 || 屏幕超时.indexOf("Exception") !== -1 || 屏幕超时.indexOf("Permission") !== -1) {
    // 回退1:非root尝试
    var 屏幕超时2 = 执行命令("settings get system screen_off_timeout", false);
    if (屏幕超时2 && 屏幕超时2.indexOf("Exception") === -1) {
      屏幕超时 = 屏幕超时2;
    } else {
      // 回退2:通过 content query 读取
      var content查询 = 执行命令("content query --uri content://settings/system --where \"name='screen_off_timeout'\"", false);
      if (content查询 && content查询.indexOf("value=") !== -1) {
            var valIdx = content查询.indexOf("value=");
            屏幕超时 = content查询.substring(valIdx + 6).split(",").trim();
      } else {
            屏幕超时 = "";
      }
    }
}
print.log("当前屏幕超时:" + (屏幕超时 || "获取失败(需 root 权限)") + " 毫秒");

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

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

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

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


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

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

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

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

// 8.4 获取 DNS 配置(多策略:resolv.conf → getprop → dhcp属性 → dumpsys解析)
print.log("\n--- 8.4 DNS 配置 ---");
var DNS1 = "";
var DNS2 = "";
// 策略1:resolv.conf
var DNS原始 = 执行命令("cat /etc/resolv.conf 2>/dev/null", false);
if (DNS原始 && DNS原始.length > 0) {
    var DNS行 = DNS原始.split("\n");
    var DNS序号 = 0;
    for (var di = 0; di < DNS行.length; di++) {
      var 行 = DNS行.trim();
      if (行.indexOf("nameserver") === 0) {
            DNS序号++;
            if (DNS序号 === 1) DNS1 = 行.substring("nameserver".length).trim();
            else if (DNS序号 === 2) DNS2 = 行.substring("nameserver".length).trim();
      }
    }
}
// 策略2:getprop net.dns
if (!DNS1) DNS1 = 执行命令("getprop net.dns1 2>/dev/null", false);
if (!DNS2) DNS2 = 执行命令("getprop net.dns2 2>/dev/null", false);
// 策略3:getprop dhcp.wlan0.dns(部分设备可用)
if (!DNS1) DNS1 = 执行命令("getprop dhcp.wlan0.dns1 2>/dev/null", false);
if (!DNS2) DNS2 = 执行命令("getprop dhcp.wlan0.dns2 2>/dev/null", false);
// 策略4:解析 dumpsys connectivity(搜索 DnsServerSearchDomains 或 dns 字样)
if (!DNS1) {
    var 连通性完整 = 执行命令("dumpsys connectivity 2>/dev/null", false);
    if (连通性完整 && 连通性完整.length > 0) {
      var 连通行 = 连通性完整.split("\n");
      for (var ci = 0; ci < 连通行.length; ci++) {
            var 连接内容 = 连通行.trim();
            if (连接内容.indexOf("DnsAddresses") !== -1 || 连接内容.indexOf("dns addresses") !== -1) {
                // 尝试提取IP地址格式 x.x.x.x
                var ipMatch = 连接内容.match(/\d+\.\d+\.\d+\.\d+/g);
                if (ipMatch) {
                  if (!DNS1) DNS1 = ipMatch;
                  if (ipMatch.length > 1 && !DNS2) DNS2 = ipMatch;
                }
            }
      }
    }
}
print.log("DNS1:" + (DNS1 || "获取失败"));
print.log("DNS2:" + (DNS2 || "获取失败"));

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


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

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

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

// 策略2:uiautomator dump(如果 auto.getXml 不可用)
if (!UI_XML) {
    执行命令静默("mkdir -p /sdcard/aiwrok_test", false);
    var UI临时文件 = "/sdcard/aiwrok_test/ui_dump.xml";
    // 先尝试 --compressed
    var dump结果1 = 执行命令("uiautomator dump --compressed " + UI临时文件 + " 2>&1", false);
    sleep.millisecond(500);
    UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
    if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
      print.log("✓ 通过 uiautomator --compressed 获取成功");
    } else {
      // 回退:不带 --compressed
      var dump结果2 = 执行命令("uiautomator dump " + UI临时文件 + " 2>&1", false);
      sleep.millisecond(500);
      UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
      if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
            print.log("✓ 通过 uiautomator dump 获取成功(非压缩模式)");
      } else {
            // 回退:尝试 /system/bin/ 完整路径
            var dump结果3 = 执行命令("/system/bin/uiautomator dump " + UI临时文件 + " 2>&1", false);
            sleep.millisecond(500);
            UI_XML = 执行命令("cat " + UI临时文件 + " 2>/dev/null", false);
            if (UI_XML && UI_XML.length > 10 && UI_XML.indexOf("<") !== -1) {
                print.log("✓ 通过 /system/bin/uiautomator 获取成功");
            } else {
                UI_XML = "";
            }
      }
    }
}

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

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

// 策略1:dumpsys window 完整输出 + JS搜索 mCurrentFocus
var 窗口完整 = 执行命令("dumpsys window 2>/dev/null", false);
if (窗口完整 && 窗口完整.length > 0) {
    var focusIndex = 窗口完整.indexOf("mCurrentFocus");
    if (focusIndex !== -1) {
      var focusLine = 窗口完整.substring(focusIndex, focusIndex + 200).split("\n");
      print.log("焦点窗口:" + focusLine);
      var spaceIdx = focusLine.indexOf(" ");
      if (spaceIdx !== -1) {
            var sub = focusLine.substring(spaceIdx + 1);
            var slashIdx = sub.indexOf("/");
            if (slashIdx !== -1) {
                前台包名 = sub.substring(0, slashIdx);
                print.log("当前前台包名:" + 前台包名);
            }
      }
    } else {
      // 回退:搜索 mFocusedApp
      var appIndex = 窗口完整.indexOf("mFocusedApp");
      if (appIndex !== -1) {
            var appLine = 窗口完整.substring(appIndex, appIndex + 200).split("\n");
            print.log("焦点应用:" + appLine);
            var appSlash = appLine.indexOf("/");
            if (appSlash !== -1) {
                var appSub = appLine.substring(appLine.indexOf(" ") + 1, appSlash);
                if (appSub) 前台包名 = appSub;
            }
      }
    }
}

// 策略2:dumpsys activity activities + JS搜索 mResumedActivity
if (!前台包名) {
    activity完整 = 执行命令("dumpsys activity activities 2>/dev/null", false);
    if (activity完整 && activity完整.length > 0) {
      var resumedIdx = activity完整.indexOf("mResumedActivity");
      if (resumedIdx !== -1) {
            var resumedLine = activity完整.substring(resumedIdx, resumedIdx + 300).split("\n");
            print.log("前台Activity:" + resumedLine);
            // 提取包名:格式通常为 mResumedActivity: ActivityRecord{... u0 com.xxx.xxx/...}
            var 包名提取 = resumedLine.match(/(\w+\.\w+\.\w+)/);
            if (包名提取) {
                前台包名 = 包名提取;
                print.log("当前前台包名(从Activity提取):" + 前台包名);
            }
      }
    }
}

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

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

// 9.3 获取 Activity 栈
print.log("\n--- 9.3 获取 Activity 栈信息 ---");
// 确保 activity完整 有值(可能在 9.2 策略2 中已获取)
if (!activity完整) {
    activity完整 = 执行命令("dumpsys activity activities 2>/dev/null", false);
}
if (activity完整 && activity完整.length > 0) {
    // 在 JS 中搜索关键字
    var 栈行 = activity完整.split("\n");
    var 栈输出 = [];
    for (var si = 0; si < 栈行.length; si++) {
      if (栈行.indexOf("Run #") !== -1 || 栈行.indexOf("mResumed") !== -1) {
            栈输出.push(栈行.trim());
      }
    }
    if (栈输出.length > 0) {
      for (var sj = 0; sj < 栈输出.length; sj++) {
            print.log("" + 栈输出);
      }
    } else {
      // 回退:输出前5行看看格式
      print.log("Activity栈:未找到 Run # 信息,输出前5行:");
      for (var sk = 0; sk < Math.min(5, 栈行.length); sk++) {
            print.log("" + 栈行.trim());
      }
    }
} else {
    print.log("Activity栈:dumpsys activity 不可用");
}


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

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

// 工具函数:获取指定包名的应用详细信息
function 获取应用详情(包名) {
    var 详情 = {
      包名: 包名,
      版本名: "",
      版本号: "",
      安装路径: "",
      数据目录: "",
      大小: "",
      是否运行: false
    };

    try {
      // 获取完整 package 信息(dumpsys 管道在部分设备返回空,改用 JS 解析)
      var 包信息完整 = 执行命令("dumpsys package " + 包名 + " 2>/dev/null", false);
      if (包信息完整 && 包信息完整.length > 0) {
            // 策略1:搜索 versionName= (标准格式)
            var vNameIdx = 包信息完整.indexOf("versionName=");
            if (vNameIdx !== -1) {
                var vNameSub = 包信息完整.substring(vNameIdx + "versionName=".length);
                详情.版本名 = vNameSub.split("\n").trim();
            }
            // 策略2:搜索 versionName (不带=,部分MIUI/HyperOS格式)
            if (!详情.版本名) {
                var vNameIdx2 = 包信息完整.indexOf("versionName ");
                if (vNameIdx2 !== -1) {
                  var vNameSub2 = 包信息完整.substring(vNameIdx2 + "versionName ".length);
                  详情.版本名 = vNameSub2.split("\n").trim();
                }
            }
            // 搜索 versionCode
            var vCodeIdx = 包信息完整.indexOf("versionCode=");
            if (vCodeIdx !== -1) {
                var vCodeSub = 包信息完整.substring(vCodeIdx + "versionCode=".length);
                详情.版本号 = vCodeSub.split(" ").trim();
            }
            if (!详情.版本号) {
                var vCodeIdx2 = 包信息完整.indexOf("versionCode ");
                if (vCodeIdx2 !== -1) {
                  var vCodeSub2 = 包信息完整.substring(vCodeIdx2 + "versionCode ".length);
                  详情.版本号 = vCodeSub2.split(" ").trim();
                }
            }
      }

      // 策略3:如果 dumpsys package 未找到,尝试 pm dump
      if (!详情.版本名) {
            var pmDump = 执行命令("pm dump " + 包名 + " 2>/dev/null", false);
            if (pmDump && pmDump.length > 0) {
                var pmVNameIdx = pmDump.indexOf("versionName=");
                if (pmVNameIdx !== -1) {
                  详情.版本名 = pmDump.substring(pmVNameIdx + "versionName=".length).split("\n").trim();
                }
                var pmVCodeIdx = pmDump.indexOf("versionCode=");
                if (pmVCodeIdx !== -1) {
                  详情.版本号 = pmDump.substring(pmVCodeIdx + "versionCode=".length).split(" ").trim();
                }
            }
      }

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

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

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

    return 详情;
}

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

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

print.log("\n--- 10.2 采集第三方应用信息(前3个)---");
var 应用列表原始 = 执行命令("pm list packages -3", false);
if (应用列表原始) {
    var 应用列表 = 应用列表原始.split("\n");
    var 采集数量 = Math.min(3, 应用列表.length);
    for (var j = 0; j < 采集数量; j++) {
      var 包名 = 应用列表.replace("package:", "").trim();
      if (包名) {
            print.log("\n应用 " + (j + 1) + ": " + 包名);
            var 详情 = 获取应用详情(包名);
            print.log("    版本名: " + 详情.版本名);
            print.log("    版本号: " + 详情.版本号);
            print.log("    安装路径: " + 详情.安装路径);
            print.log("    是否运行: " + (详情.是否运行 ? "是 ✓" : "否"));
      }
    }
}


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

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

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

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

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

      // 策略2:如果 sysfs 为空,用 dumpsys battery 解析(不用管道grep,直接JS搜索)
      if (!电池.电量) {
            var dumpsys电池 = 执行命令("dumpsys battery 2>/dev/null", false);
            if (dumpsys电池 && dumpsys电池.length > 0) {
                var 电池行 = dumpsys电池.split("\n");
                for (var bi = 0; bi < 电池行.length; bi++) {
                  var 行内容 = 电池行.trim();
                  if (行内容.indexOf("level:") !== -1 && !电池.电量) {
                        电池.电量 = 行内容.replace("level:", "").trim();
                  }
                  if (行内容.indexOf("temperature:") !== -1 && !电池.温度) {
                        var 温度提取 = parseInt(行内容.replace("temperature:", "").trim(), 10);
                        电池.温度 = isNaN(温度提取) ? "" : (温度提取 / 10) + "°C";
                  }
                  if (行内容.indexOf("status:") !== -1 && !电池.状态) {
                        var 状态提取 = 行内容.replace("status:", "").trim();
                        电池.状态 = 状态映射[状态提取] || 状态提取 || "";
                  }
                  if (行内容.indexOf("technology:") !== -1 && !电池.技术) {
                        电池.技术 = 行内容.replace("technology:", "").trim();
                  }
                }
            }
      }

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

// 工具函数:获取网络流量统计
function 获取网络流量() {
    try {
      // 获取 wlan0 接口的流量统计
      var 流量 = 执行命令("cat /proc/net/dev | grep wlan0", false);
      if (流量) {
            // /proc/net/dev 格式: "wlan0: rx_bytes rx_packets ... tx_bytes tx_packets ..."
            // trim 后 split: 字段="wlan0:" 字段=rx_bytes 字段=rx_packets ... 字段=tx_bytes 字段=tx_packets
            var 字段 = 流量.trim().split(/\s+/);
            if (字段.length >= 11) {
                return {
                  接收字节: 字段,
                  接收包数: 字段,
                  发送字节: 字段,
                  发送包数: 字段
                };
            }
      }
    } catch (e) {
      print.log("⚠ 获取网络流量失败: " + e.message);
    }
    return null;
}

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

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

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

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


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

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

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

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

// 工具函数:强制停止所有第三方后台应用
function 停止后台应用() {
    var 停止数量 = 0;
    try {
      var 应用列表 = 执行命令("pm list packages -3", false);
      if (应用列表) {
            var 应用 = 应用列表.split("\n");
            for (var q = 0; q < 应用.length; q++) {
                var 包名 = 应用.replace("package:", "").trim();
                if (包名) {
                  // 检查是否在运行
                  var 进程 = 执行命令("ps | grep " + 包名, false);
                  if (进程 && 进程.length > 0) {
                        // 强制停止
                        执行命令静默("am force-stop " + 包名, false);
                        print.log("✓ 已停止: " + 包名);
                        停止数量++;
                  }
                }
            }
      }
    } catch (e) {
      print.log("⚠ 停止后台应用失败: " + e.message);
    }
    return 停止数量;
}

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

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

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

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


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

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

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

function 智能执行(命令, 需要root) {
    var 结果 = "";
    try {
      // 优先使用 adb.exec
      if (typeof adb !== "undefined" && adb.exec) {
            var 原始 = adb.exec(命令, 需要root || false);
            结果 = 清洗输出(String(原始));
            print.log(" " + 命令 + " → " + 结果.substring(0, 50));
      }
      // 回退到 agent.shell
      else if (typeof agent !== "undefined" && agent.shell) {
            结果 = String(agent.shell(命令));
            print.log(" " + 命令 + " → " + 结果.substring(0, 50));
      }
      // 回退到 shell.exec
      else if (typeof shell !== "undefined" && shell.exec) {
            结果 = String(shell.exec(命令));
            print.log(" " + 命令 + " → " + 结果.substring(0, 50));
      }
      else {
            print.log("⚠ 无可用的命令执行接口");
      }
    } catch (e) {
      print.log("⚠ 智能执行异常: " + e.message);
    }
    return 结果;
}

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


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

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

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

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

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

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

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

    // 采集前台应用(管道grep返回空,改用JS解析dumpsys window完整输出)
    var 监控窗口 = 执行命令("dumpsys window 2>/dev/null", false);
    if (监控窗口 && 监控窗口.length > 0) {
      var focusIdx = 监控窗口.indexOf("mCurrentFocus");
      if (focusIdx !== -1) {
            var focus行 = 监控窗口.substring(focusIdx, focusIdx + 200).split("\n");
            print.log("前台: " + focus行);
      } else {
            // 回退:搜索 mFocusedApp
            var appIdx = 监控窗口.indexOf("mFocusedApp");
            if (appIdx !== -1) {
                var app行 = 监控窗口.substring(appIdx, appIdx + 200).split("\n");
                print.log("前台: " + app行);
            } else {
                print.log("前台: 未获取到焦点窗口");
            }
      }
    } else {
      print.log("前台: dumpsys window 不可用");
    }

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

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

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


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

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

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

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

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

    return 结果;
}

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

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


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

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


页: [1]
查看完整版本: adb.exec() 高级用法完整示例