自动发帖软件
标题:
AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
[打印本页]
作者:
发帖软件
时间:
昨天 07:31
标题:
AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
1.png
(1.38 MB, 下载次数: 0)
昨天 07:30
上传
// =============================================================================
// AIWROK adb.exec() 实用工具库 —— 常用功能直接调用版
// =============================================================================
// 适用平台:AIWROK 安卓自动化软件
// 引擎:Rhino (ES5)
// 说明:从 adb_exec高级用法示例.js 中抽取最常用的功能,
// 封装成可直接调用的工具函数,拿来即用。
//
// adb.exec(command, isRoot) 参数说明:
// - command: shell 命令字符串
// - isRoot: true=以 root 权限执行(su -c), false=普通权限
// - 返回值: JSON 格式 {"errorMsg":"","success":"实际内容"}
//
// 使用方式:
// 方式1:直接运行本脚本 → 查看各功能演示输出
// 方式2:将本文件内容复制到你的项目中 → 调用 AdbUtil.方法名()
// =============================================================================
print.log("===== adb.exec() 实用工具库 =====\n");
// =============================================================================
// 核心工具层:返回值清洗 + 安全执行
// =============================================================================
/**
* 清洗 adb.exec 返回值
* 处理两种格式:JSON {"success":"..."} 和旧格式 successMsg:...,errorMsg:...
*/
function 清洗输出(原始结果) {
if (!原始结果) return "";
var 结果 = String(原始结果);
// 格式1: JSON {"errorMsg":"","success":"实际内容"}
if (结果.charAt(0) === "{") {
try {
var json = JSON.parse(结果);
if (json && json.success !== undefined) {
// 过滤 Broken pipe 警告(| head/grep 提前关闭管道导致,不影响实际结果)
if (json.errorMsg && json.errorMsg !== "" &&
json.errorMsg.indexOf("Broken pipe") === -1 &&
json.errorMsg.indexOf("Failed to write") === -1) {
print.log(" [警告] 命令错误: " + json.errorMsg);
}
return String(json.success).trim();
}
} catch (e) {
// JSON.parse 失败,正则提取 success 字段
var m = 结果.match(/"success"\s*:\s*"([\s\S]*?)"\s*[,}]/);
if (m) {
return m[1].replace(/\\n/g, "\n").replace(/\\t/g, "\t")
.replace(/\\"/g, '"').replace(/\\\\/g, "\\").trim();
}
}
return 结果.trim();
}
// 格式2: 旧格式 successMsg:内容,errorMsg:内容
if (结果.indexOf("successMsg:") === 0) {
结果 = 结果.substring("successMsg:".length);
}
var 错误索引 = 结果.indexOf(",errorMsg:");
if (错误索引 !== -1) {
结果 = 结果.substring(0, 错误索引);
}
return 结果.trim();
}
/**
* 安全执行命令并返回清洗后的结果
* @param {string} 命令 - shell 命令
* @param {boolean} 是否root - 是否以 root 权限执行
* @returns {string} 清洗后的输出
*/
function 执行命令(命令, 是否root) {
try {
var 原始 = adb.exec(命令, 是否root || false);
return 清洗输出(String(原始));
} catch (e) {
print.log(" [异常] " + 命令 + " → " + e.message);
return "";
}
}
/**
* 安全执行命令(不关心返回值,只关心是否成功)
* @returns {boolean} 是否执行无异常
*/
function 执行命令静默(命令, 是否root) {
try {
adb.exec(命令, 是否root || false);
return true;
} catch (e) {
return false;
}
}
// =============================================================================
// 模块一:设备信息采集
// =============================================================================
var AdbUtil = {};
/**
* 获取设备基础信息(型号/品牌/安卓版本/SDK/序列号)
* @returns {Object} 设备信息对象
*/
AdbUtil.获取设备信息 = function() {
return {
型号: 执行命令("getprop ro.product.model", false),
品牌: 执行命令("getprop ro.product.brand", false),
安卓版本: 执行命令("getprop ro.build.version.release", false),
SDK版本: 执行命令("getprop ro.build.version.sdk", false),
制造商: 执行命令("getprop ro.product.manufacturer", false),
序列号: 执行命令("getprop ro.serialno", false)
};
};
/**
* 获取屏幕分辨率和密度
* @returns {Object} {分辨率:"Physical size: 1080x2400", 密度:"Physical density: 440"}
*/
AdbUtil.获取屏幕信息 = function() {
return {
分辨率: 执行命令("wm size", false),
密度: 执行命令("wm density", false)
};
};
/**
* 获取电池信息(多策略:dumpsys battery → sysfs 文件解析)
* @returns {Object} {电量:"85", 温度:"32.5°C", 状态:"充电中", 技术:"Li-ion"}
*/
AdbUtil.获取电池信息 = function() {
var 电池 = { 电量: "", 温度: "", 状态: "", 技术: "" };
var 状态映射 = {
"Charging": "充电中", "Discharging": "放电中",
"Full": "已充满", "Not charging": "未充电",
"2": "充电中", "3": "放电中", "4": "已充满", "5": "未充电"
};
// 策略1:dumpsys battery(需要 root 权限,普通权限缺少 DUMP 权限)
var 电池原始 = 执行命令("dumpsys battery", true);
if (电池原始 && 电池原始.length > 0 && 电池原始.indexOf("Permission Denial") === -1) {
var 行1 = 电池原始.split("\n");
for (var i = 0; i < 行1.length; i++) {
var r = 行1[i].trim();
if (r.indexOf("level:") !== -1)
电池.电量 = r.replace("level:", "").trim();
if (r.indexOf("temperature:") !== -1) {
var t = parseInt(r.replace("temperature:", "").trim(), 10);
电池.温度 = isNaN(t) ? "" : (t / 10) + "°C";
}
if (r.indexOf("status:") !== -1) {
var s = r.replace("status:", "").trim();
电池.状态 = 状态映射[s] || s || "";
}
if (r.indexOf("technology:") !== -1)
电池.技术 = r.replace("technology:", "").trim();
}
}
// 策略2:sysfs 文件系统(root 权限,路径可能因设备不同而异)
if (!电池.电量) {
var 路径列表 = [
"/sys/class/power_supply/battery",
"/sys/class/power_supply/bms",
"/sys/class/power_supply/max170xx_battery"
];
for (var pi = 0; pi < 路径列表.length && !电池.电量; pi++) {
var 基础路径 = 路径列表[pi];
var cap = 执行命令("cat " + 基础路径 + "/capacity", true);
if (cap && /^\d+$/.test(cap.trim())) 电池.电量 = cap.trim();
var 温度原始 = 执行命令("cat " + 基础路径 + "/temp", true);
if (温度原始 && /^\d+$/.test(温度原始.trim())) {
var t2 = parseInt(温度原始.trim(), 10);
电池.温度 = isNaN(t2) ? "" : (t2 / 10) + "°C";
}
var 状态原始 = 执行命令("cat " + 基础路径 + "/status", true);
if (状态原始 && 状态原始.indexOf("No such") === -1 && 状态原始.indexOf("Permission") === -1)
电池.状态 = 状态映射[状态原始.trim()] || 状态原始.trim() || "";
var 技术原始 = 执行命令("cat " + 基础路径 + "/technology", true);
if (技术原始 && 技术原始.indexOf("No such") === -1 && 技术原始.indexOf("Permission") === -1)
电池.技术 = 技术原始.trim();
}
}
return 电池;
};
/**
* 获取内存信息
* @returns {string} MemTotal / MemFree / MemAvailable 行
*/
AdbUtil.获取内存信息 = function() {
return 执行命令("cat /proc/meminfo | head -3", false);
};
/**
* 获取存储信息
* @returns {string} df 输出
*/
AdbUtil.获取存储信息 = function() {
return 执行命令("df /sdcard", false);
};
// =============================================================================
// 模块二:应用管理
// =============================================================================
/**
* 列出所有第三方应用包名
* @returns {Array} 包名数组,如 ["com.tencent.mm", "com.taobao.taobao", ...]
*/
AdbUtil.列出第三方应用 = function() {
var 输出 = 执行命令("pm list packages -3", false);
if (!输出) return [];
var 行 = 输出.split("\n");
var 结果 = [];
for (var i = 0; i < 行.length; i++) {
var 包名 = 行[i].replace("package:", "").trim();
if (包名) 结果.push(包名);
}
return 结果;
};
/**
* 检查应用是否已安装
* @param {string} 包名 - 应用包名
* @returns {boolean} 是否已安装
*/
AdbUtil.应用是否安装 = function(包名) {
var 结果 = 执行命令("pm list packages " + 包名, false);
return !!(结果 && 结果.indexOf(包名) !== -1);
};
/**
* 启动应用
* @param {string} 包名 - 应用包名
* @returns {boolean} 是否执行成功
*/
AdbUtil.启动应用 = function(包名) {
// 方式1:monkey 启动(最通用)
var 结果 = 执行命令静默("monkey -p " + 包名 + " 1 2>/dev/null", false);
if (结果) return true;
// 方式2:am start(需要知道主 Activity,这里用包名尝试)
return 执行命令静默("am start -n " + 包名 + "/.MainActivity 2>/dev/null", false);
};
/**
* 通过 Action 启动系统页面
* @param {string} action - Android action 常量
* @returns {boolean}
*/
AdbUtil.启动Action = function(action) {
return 执行命令静默("am start -a " + action, false);
};
/**
* 强制停止应用
* @param {string} 包名
* @returns {boolean}
*/
AdbUtil.停止应用 = function(包名) {
return 执行命令静默("am force-stop " + 包名, false);
};
/**
* 安装 APK
* @param {string} apk路径 - APK 文件路径,如 /sdcard/app.apk
* @param {boolean} 覆盖安装 - true 使用 -r 覆盖安装
* @returns {boolean}
*/
AdbUtil.安装应用 = function(apk路径, 覆盖安装) {
var 参数 = 覆盖安装 ? "-r " : "";
var 结果 = 执行命令("pm install " + 参数 + apk路径, false);
return !!(结果 && 结果.indexOf("Success") !== -1);
};
/**
* 卸载应用
* @param {string} 包名
* @returns {boolean}
*/
AdbUtil.卸载应用 = function(包名) {
var 结果 = 执行命令("pm uninstall " + 包名, false);
return !!(结果 && 结果.indexOf("Success") !== -1);
};
/**
* 获取应用版本信息
* @param {string} 包名
* @returns {Object} {版本名:"1.0.0", 版本号:"10", 安装路径:"/data/app/..."}
*/
AdbUtil.获取应用信息 = function(包名) {
var 信息 = { 版本名: "", 版本号: "", 安装路径: "" };
// 策略1:pm path 获取安装路径(轻量命令,不卡死)
var 路径 = 执行命令("pm path " + 包名, false);
if (路径) 信息.安装路径 = 路径.replace("package:", "").trim();
// 策略2:dumpsys package | grep version(grep 读取完整输出但只输出匹配行,JSON返回值很小)
// 注意:不能用 head 截断(版本信息在输出末尾的 Packages 段,head 会截掉)
var 版本输出 = 执行命令("dumpsys package " + 包名 + " | grep version", true);
if (版本输出 && 版本输出.length > 0 && 版本输出.indexOf("Permission Denial") === -1) {
var 行数组 = 版本输出.split("\n");
for (var i = 0; i < 行数组.length; i++) {
var r = 行数组[i].trim();
if (r.indexOf("versionName=") !== -1 && !信息.版本名) {
信息.版本名 = r.replace("versionName=", "").split(" ")[0].trim();
} else if (r.indexOf("versionName ") !== -1 && !信息.版本名) {
信息.版本名 = r.replace("versionName ", "").split(" ")[0].trim();
}
if (r.indexOf("versionCode=") !== -1 && !信息.版本号) {
信息.版本号 = r.replace("versionCode=", "").split(" ")[0].trim();
} else if (r.indexOf("versionCode ") !== -1 && !信息.版本号) {
信息.版本号 = r.replace("versionCode ", "").split(" ")[0].trim();
}
// 也处理 "versionName=xxx" 格式(不带空格的整行)
if (r.indexOf("versionName=") !== -1 && !信息.版本名) {
var m = r.match(/versionName=(\S+)/);
if (m) 信息.版本名 = m[1];
}
if (r.indexOf("versionCode=") !== -1 && !信息.版本号) {
var m2 = r.match(/versionCode=(\S+)/);
if (m2) 信息.版本号 = m2[1];
}
}
}
// 策略3:pm dump | grep version(回退方案)
if (!信息.版本名) {
var pm输出 = 执行命令("pm dump " + 包名 + " | grep version", true);
if (pm输出 && pm输出.length > 0 && pm输出.indexOf("Permission Denial") === -1) {
var pm行 = pm输出.split("\n");
for (var j = 0; j < pm行.length; j++) {
var pr = pm行[j].trim();
if (pr.indexOf("versionName=") !== -1 && !信息.版本名) {
var pmM = pr.match(/versionName=(\S+)/);
if (pmM) 信息.版本名 = pmM[1];
}
if (pr.indexOf("versionCode=") !== -1 && !信息.版本号) {
var pmM2 = pr.match(/versionCode=(\S+)/);
if (pmM2) 信息.版本号 = pmM2[1];
}
}
}
}
return 信息;
};
// =============================================================================
// 模块三:文件操作
// =============================================================================
/**
* 列出目录内容
* @param {string} 目录路径
* @returns {string} ls -la 输出
*/
AdbUtil.列目录 = function(目录路径) {
return 执行命令("ls -la " + 目录路径, false);
};
/**
* 读取文件内容
* @param {string} 文件路径
* @returns {string} 文件内容
*/
AdbUtil.读文件 = function(文件路径) {
return 执行命令("cat " + 文件路径 + " 2>/dev/null", false);
};
/**
* 写入文件(覆盖写入)
* @param {string} 文件路径
* @param {string} 内容 - 仅支持不含单引号的内容,含单引号需自行转义
* @returns {boolean}
*/
AdbUtil.写文件 = function(文件路径, 内容) {
return 执行命令静默("echo '" + 内容 + "' > " + 文件路径, false);
};
/**
* 追加写入文件
* @param {string} 文件路径
* @param {string} 内容
* @returns {boolean}
*/
AdbUtil.追加写文件 = function(文件路径, 内容) {
return 执行命令静默("echo '" + 内容 + "' >> " + 文件路径, false);
};
/**
* 复制文件
* @param {string} 源路径
* @param {string} 目标路径
* @returns {boolean}
*/
AdbUtil.复制文件 = function(源路径, 目标路径) {
return 执行命令静默("cp " + 源路径 + " " + 目标路径 + " 2>/dev/null", false);
};
/**
* 创建目录(递归创建)
* @param {string} 目录路径
* @returns {boolean}
*/
AdbUtil.创建目录 = function(目录路径) {
return 执行命令静默("mkdir -p " + 目录路径, false);
};
/**
* 删除文件或目录
* @param {string} 路径
* @returns {boolean}
*/
AdbUtil.删除 = function(路径) {
return 执行命令静默("rm -rf " + 路径 + " 2>/dev/null", false);
};
/**
* 获取文件大小(字节)
* @param {string} 文件路径
* @returns {number} 文件大小(字节),失败返回 -1
*/
AdbUtil.文件大小 = function(文件路径) {
var 结果 = 执行命令("stat -c %s " + 文件路径 + " 2>/dev/null", false);
var 大小 = parseInt(结果.trim(), 10);
return isNaN(大小) ? -1 : 大小;
};
// =============================================================================
// 模块四:输入模拟
// =============================================================================
/**
* 模拟点击坐标
* @param {number} x - X 坐标
* @param {number} y - Y 坐标
* @returns {boolean}
*/
AdbUtil.点击 = function(x, y) {
return 执行命令静默("input tap " + x + " " + y, false);
};
/**
* 模拟滑动
* @param {number} x1 - 起点 X
* @param {number} y1 - 起点 Y
* @param {number} x2 - 终点 X
* @param {number} y2 - 终点 Y
* @param {number} 时长 - 滑动时长(毫秒),默认 300
* @returns {boolean}
*/
AdbUtil.滑动 = function(x1, y1, x2, y2, 时长) {
时长 = 时长 || 300;
return 执行命令静默("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " " + 时长, false);
};
/**
* 模拟长按(起点终点相同,时长 > 500ms)
* @param {number} x
* @param {number} y
* @param {number} 时长 - 长按时长(毫秒),默认 1000
* @returns {boolean}
*/
AdbUtil.长按 = function(x, y, 时长) {
时长 = 时长 || 1000;
return 执行命令静默("input swipe " + x + " " + y + " " + x + " " + y + " " + 时长, false);
};
/**
* 模拟输入文字(仅支持 ASCII)
* @param {string} 文字
* @returns {boolean}
*/
AdbUtil.输入文字 = function(文字) {
// input text 不支持空格,需用 %s 替代
var 替换 = 文字.replace(/ /g, "%s");
return 执行命令静默("input text '" + 替换 + "'", false);
};
/**
* 模拟按键事件
* @param {number|string} 键码 - KeyEvent 键码,如 4=返回, 3=Home, 26=电源
* @returns {boolean}
*
* 常用键码速查:
* 3=HOME 4=BACK 5=呼叫 6=挂断 24=音量+ 25=音量-
* 26=电源 27=相机 66=回车 82=菜单 84=搜索 279=粘贴
*/
AdbUtil.按键 = function(键码) {
return 执行命令静默("input keyevent " + 键码, false);
};
/**
* 模拟返回键
*/
AdbUtil.返回键 = function() {
return AdbUtil.按键(4);
};
/**
* 模拟 Home 键
*/
AdbUtil.Home键 = function() {
return AdbUtil.按键(3);
};
// =============================================================================
// 模块五:前台应用检测 + 进程管理
// =============================================================================
/**
* 获取当前前台包名(多策略:dumpsys window → dumpsys activity → 原生方法)
* @returns {string} 前台包名,如 "com.tencent.mm"
*/
AdbUtil.获取前台包名 = function() {
// 策略1:dumpsys activity activities | head -50(限制输出防止卡死,mResumedActivity在前30行内)
var activity输出 = 执行命令("dumpsys activity activities | head -50", true);
if (activity输出 && activity输出.length > 0 && activity输出.indexOf("Permission Denial") === -1) {
var 行数组 = activity输出.split("\n");
for (var fi = 0; fi < 行数组.length; fi++) {
var 行 = 行数组[fi].trim();
if (行.indexOf("mResumedActivity") !== -1 ||
行.indexOf("topResumedActivity") !== -1 ||
行.indexOf("ResumedActivity") !== -1) {
var 斜杠 = 行.indexOf("/");
if (斜杠 !== -1) {
var 前段 = 行.substring(0, 斜杠);
var 空格 = 前段.lastIndexOf(" ");
if (空格 !== -1) {
var 包名 = 前段.substring(空格 + 1).trim();
if (包名 && 包名.indexOf(".") !== -1) return 包名;
}
}
}
}
}
// 策略2:dumpsys window | head -30(限制输出防止卡死,mCurrentFocus在前10行内)
var window输出 = 执行命令("dumpsys window | head -30", true);
if (window输出 && window输出.length > 0 && window输出.indexOf("Permission Denial") === -1) {
var win行 = window输出.split("\n");
for (var wi = 0; wi < win行.length; wi++) {
var w行 = win行[wi].trim();
if (w行.indexOf("mCurrentFocus") !== -1 ||
w行.indexOf("mFocusedApp") !== -1 ||
w行.indexOf("mFocusedWindow") !== -1) {
var w斜杠 = w行.indexOf("/");
if (w斜杠 !== -1) {
var w前段 = w行.substring(0, w斜杠);
var w空格 = w前段.lastIndexOf(" ");
if (w空格 !== -1) {
var w包名 = w前段.substring(w空格 + 1).trim();
if (w包名 && w包名.indexOf(".") !== -1) return w包名;
}
}
}
}
}
// 策略3:AIWROK 原生方法
try {
if (typeof auto !== "undefined") {
if (auto.getTopPackName) {
var p = String(auto.getTopPackName());
if (p && p.length > 0) return p;
}
}
} catch (e) {}
return "";
};
/**
* 获取当前前台 Activity 全名
* @returns {string} 如 "com.tencent.mm/.ui.LauncherUI"
*/
AdbUtil.获取前台Activity = function() {
// 策略1:dumpsys activity activities | head -50(限制输出防止卡死)
var activity输出 = 执行命令("dumpsys activity activities | head -50", true);
if (activity输出 && activity输出.length > 0 && activity输出.indexOf("Permission Denial") === -1) {
var 行数组 = activity输出.split("\n");
for (var fi = 0; fi < 行数组.length; fi++) {
var 行 = 行数组[fi].trim();
if (行.indexOf("mResumedActivity") !== -1 ||
行.indexOf("topResumedActivity") !== -1) {
var m = 行.match(/(\w+\.\w+\.\w+\/\S+)/);
if (m) return m[1].replace(/[}]/g, "").trim();
}
}
}
// 策略2:dumpsys window | head -30(限制输出防止卡死)
var window输出 = 执行命令("dumpsys window | head -30", true);
if (window输出 && window输出.length > 0 && window输出.indexOf("Permission Denial") === -1) {
var win行 = window输出.split("\n");
for (var wi = 0; wi < win行.length; wi++) {
var w行 = win行[wi].trim();
if (w行.indexOf("mCurrentFocus") !== -1 ||
w行.indexOf("mFocusedApp") !== -1) {
var m2 = w行.match(/(\w+\.\w+\.\w+\/\S+)/);
if (m2) return m2[1].replace(/[}]/g, "").trim();
}
}
}
return "";
};
/**
* 检查指定应用是否在前台
* @param {string} 包名
* @returns {boolean}
*/
AdbUtil.是否在前台 = function(包名) {
var 前台 = AdbUtil.获取前台包名();
return 前台 === 包名;
};
/**
* 检查指定进程是否在运行
* @param {string} 包名或进程名
* @returns {boolean}
*/
AdbUtil.进程是否存在 = function(包名) {
// 策略1:ps -A | grep(需要 root 权限,Android 14 普通权限只能看到当前会话进程)
var 结果 = 执行命令("ps -A | grep " + 包名, true);
if (结果 && 结果.length > 0 && 结果.indexOf(包名) !== -1) return true;
// 策略2:pgrep -f(需要 root 权限)
var pgrep结果 = 执行命令("pgrep -f " + 包名, true);
if (pgrep结果 && pgrep结果.length > 0 && /^\d+/.test(pgrep结果.trim())) return true;
// 策略3:pidof(需要 root 权限)
var pidof结果 = 执行命令("pidof " + 包名, true);
if (pidof结果 && pidof结果.length > 0 && pidof结果.indexOf("pidof:") === -1 && /^\d+/.test(pidof结果.trim())) return true;
// 策略4:ps -A 全量输出在 JS 中搜索(root 权限)
var ps输出 = 执行命令("ps -A", true);
if (ps输出 && ps输出.length > 0) {
var ps行 = ps输出.split("\n");
for (var pi = 0; pi < ps行.length; pi++) {
if (ps行[pi].indexOf(包名) !== -1) return true;
}
}
return false;
};
/**
* 获取 CPU 占用最高的进程
* @returns {string} top 命令前 15 行
*/
AdbUtil.获取CPU占用 = function() {
// 需要 root 权限,普通权限 top 只显示当前会话的 3 个进程
return 执行命令("top -n 1 -b | head -15", true);
};
/**
* 杀死指定进程(需要 root 或同 UID)
* @param {number|string} pid - 进程 ID 或包名
* @param {boolean} 是否root
* @returns {boolean}
*/
AdbUtil.杀死进程 = function(pid, 是否root) {
// 如果传入的是包名,先获取 PID(需要 root 权限)
if (typeof pid === "string" && pid.indexOf(".") !== -1) {
var ps结果 = 执行命令("ps -A | grep " + pid, true);
if (ps结果 && ps结果.indexOf(pid) !== -1) {
var 字段 = ps结果.trim().split(/\s+/);
if (字段.length >= 2) pid = 字段[1]; // ps 输出第二列是 PID
}
}
return 执行命令静默("kill " + pid, 是否root || true);
};
// =============================================================================
// 模块六:截图 + 网络诊断
// =============================================================================
/**
* 截图保存到文件
* @param {string} 保存路径 - 如 /sdcard/screenshot.png
* @returns {boolean} 是否成功
*/
AdbUtil.截图 = function(保存路径) {
保存路径 = 保存路径 || ("/sdcard/screenshot_" + Date.now() + ".png");
// 策略1:screencap 普通权限(增加延时确保文件写入完成)
执行命令静默("screencap -p " + 保存路径, false);
sleep.millisecond(1000);
var 大小1 = AdbUtil.文件大小(保存路径);
if (大小1 > 0) {
print.log(" 截图已保存: " + 保存路径);
return true;
}
// 策略2:screencap root 权限
执行命令静默("screencap -p " + 保存路径, true);
sleep.millisecond(1000);
var 大小2 = AdbUtil.文件大小(保存路径);
if (大小2 > 0) {
print.log(" 截图已保存(root): " + 保存路径);
return true;
}
// 策略3:先截图到临时文件再复制(部分设备 screencap 不支持直接写 sdcard)
var 临时路径 = "/data/local/tmp/screenshot_tmp.png";
执行命令静默("screencap -p " + 临时路径, false);
sleep.millisecond(1000);
var 大小3 = AdbUtil.文件大小(临时路径);
if (大小3 > 0) {
执行命令静默("cp " + 临时路径 + " " + 保存路径, false);
sleep.millisecond(300);
执行命令静默("rm -f " + 临时路径, false);
print.log(" 截图已保存(临时文件中转): " + 保存路径);
return true;
}
// 策略4:使用 input keyevent 120 (KEYCODE_SYSRQ) 截屏系统快捷键
执行命令静默("input keyevent 120", false);
sleep.millisecond(1500);
// 系统截图默认保存到 /sdcard/Pictures/Screenshots/
var 系统截图目录 = 执行命令("ls -t /sdcard/Pictures/Screenshots/ | head -1", false);
if (系统截图目录 && 系统截图目录.length > 0) {
var 系统截图路径 = "/sdcard/Pictures/Screenshots/" + 系统截图目录.trim();
var 系统大小 = AdbUtil.文件大小(系统截图路径);
if (系统大小 > 0) {
执行命令静默("cp " + 系统截图路径 + " " + 保存路径, false);
sleep.millisecond(300);
print.log(" 截图已保存(系统快捷键): " + 保存路径);
return true;
}
}
print.log(" 截图失败(screencap 不可用或权限不足)");
return false;
};
/**
* Ping 测试
* @param {string} 地址 - 域名或 IP,默认 www.baidu.com
* @param {number} 次数 - ping 次数,默认 3
* @returns {string} ping 输出
*/
AdbUtil.Ping = function(地址, 次数) {
地址 = 地址 || "www.baidu.com";
次数 = 次数 || 3;
return 执行命令("ping -c " + 次数 + " " + 地址, false);
};
/**
* 获取 WiFi IP 地址
* @returns {string} 如 "192.168.1.100"
*/
AdbUtil.获取WiFiIP = function() {
var 输出 = 执行命令("ip addr show wlan0 2>/dev/null", false);
if (输出) {
var m = 输出.match(/inet\s+(\d+\.\d+\.\d+\.\d+)/);
if (m) return m[1];
}
return "";
};
/**
* 获取网络接口信息
* @returns {string} ip addr 输出
*/
AdbUtil.获取网络接口 = function() {
return 执行命令("ip addr", false);
};
/**
* 获取路由表
* @returns {string}
*/
AdbUtil.获取路由表 = function() {
return 执行命令("ip route", false);
};
// =============================================================================
// 模块七:系统设置(部分需要 root)
// =============================================================================
/**
* 获取系统设置值
* @param {string} 命名空间 - "system" / "secure" / "global"
* @param {string} 键名 - 设置键名
* @param {boolean} 是否root
* @returns {string} 设置值
*/
AdbUtil.获取设置 = function(命名空间, 键名, 是否root) {
// 策略1:settings get
var 结果 = 执行命令("settings get " + 命名空间 + " " + 键名, 是否root || false);
if (结果 && 结果.indexOf("Exception") === -1 && 结果.indexOf("null") !== 0) {
return 结果.trim();
}
// 策略2:content query(非 root 回退)
var 查询 = 执行命令(
"content query --uri content://settings/" + 命名空间 +
" --where \"name='" + 键名 + "'\"", false
);
if (查询 && 查询.indexOf("value=") !== -1) {
var vIdx = 查询.indexOf("value=");
return 查询.substring(vIdx + 6).split(",")[0].trim();
}
return "";
};
/**
* 修改系统设置值(通常需要 root)
* @param {string} 命名空间
* @param {string} 键名
* @param {string} 值
* @param {boolean} 是否root
* @returns {boolean}
*/
AdbUtil.设置值 = function(命名空间, 键名, 值, 是否root) {
return 执行命令静默(
"settings put " + 命名空间 + " " + 键名 + " " + 值,
是否root || false
);
};
/**
* 获取屏幕超时时间(毫秒)
* @returns {string}
*/
AdbUtil.获取屏幕超时 = function() {
return AdbUtil.获取设置("system", "screen_off_timeout", true);
};
/**
* 设置屏幕超时时间
* @param {number} 毫秒 - 超时时间,如 60000=60秒
* @returns {boolean}
*/
AdbUtil.设置屏幕超时 = function(毫秒) {
return AdbUtil.设置值("system", "screen_off_timeout", 毫秒, true);
};
// =============================================================================
// 综合实战演示 —— 全部功能运行一遍,每个功能前 3 秒倒计时
// =============================================================================
/**
* 3秒倒计时函数 —— 每个功能前执行,增加节奏感
* @param {string} 功能名称 - 即将执行的功能名称
*/
function 倒计时(功能名称) {
print.log("\n────────────────────────────────────────");
print.log(" 即将执行: " + 功能名称);
for (var i = 3; i > 0; i--) {
print.log(" ⏳ 倒计时 " + i + " 秒...");
sleep.second(1);
}
print.log(" ▶ 开始执行: " + 功能名称);
print.log("────────────────────────────────────────\n");
}
print.log("╔════════════════════════════════════════╗");
print.log("║ adb.exec() 全功能实机运行演示 ║");
print.log("║ 共 12 个功能模块,每个间隔 3 秒倒计时 ║");
print.log("╚════════════════════════════════════════╝\n");
// ===== 演示1:设备信息一键采集 =====
倒计时("演示1 / 设备信息一键采集");
print.log("【演示1】设备信息一键采集");
var 设备 = AdbUtil.获取设备信息();
print.log(" 型号: " + 设备.型号);
print.log(" 品牌: " + 设备.品牌);
print.log(" 安卓版本: " + 设备.安卓版本 + " (SDK " + 设备.SDK版本 + ")");
print.log(" 制造商: " + 设备.制造商);
print.log(" 序列号: " + 设备.序列号);
var 屏幕 = AdbUtil.获取屏幕信息();
print.log(" 分辨率: " + 屏幕.分辨率);
print.log(" 密度: " + 屏幕.密度);
var 电池 = AdbUtil.获取电池信息();
print.log(" 电量: " + (电池.电量 || "?") + "% | 温度: " + (电池.温度 || "?") + " | 状态: " + (电池.状态 || "?"));
print.log(" 电池技术: " + (电池.技术 || "?"));
// 诊断:如果电池信息为空,打印 dumpsys battery 前5行帮助排查
if (!电池.电量) {
print.log(" [诊断] dumpsys battery 前5行:");
var 诊断电池 = 执行命令("dumpsys battery", true);
if (诊断电池 && 诊断电池.length > 0) {
var 诊断行 = 诊断电池.split("\n");
for (var di = 0; di < Math.min(5, 诊断行.length); di++) {
print.log(" " + 诊断行[di].trim());
}
} else {
print.log(" dumpsys battery 返回空!");
}
}
var 内存 = AdbUtil.获取内存信息();
print.log(" 内存信息:");
var 内存行 = 内存.split("\n");
for (var mi = 0; mi < 内存行.length; mi++) {
if (内存行[mi].trim()) print.log(" " + 内存行[mi].trim());
}
print.log("✅ 演示1 完成");
// ===== 演示2:前台应用检测 =====
倒计时("演示2 / 前台应用检测");
print.log("【演示2】前台应用检测");
var 前台包名 = AdbUtil.获取前台包名();
print.log(" 当前前台包名: " + (前台包名 || "获取失败"));
var 前台Activity = AdbUtil.获取前台Activity();
print.log(" 当前前台Activity: " + (前台Activity || "获取失败"));
// 诊断:如果前台包名为空,打印 dumpsys activity activities 中包含 Resumed 的行
if (!前台包名) {
print.log(" [诊断] dumpsys activity activities 中 Resumed 相关行:");
var 诊断activity = 执行命令("dumpsys activity activities | head -100", true);
if (诊断activity && 诊断activity.length > 0) {
var 诊断行 = 诊断activity.split("\n");
var 找到 = 0;
for (var di2 = 0; di2 < 诊断行.length && 找到 < 3; di2++) {
if (诊断行[di2].indexOf("Resumed") !== -1 ||
诊断行[di2].indexOf("resumed") !== -1 ||
诊断行[di2].indexOf("topResumed") !== -1) {
print.log(" " + 诊断行[di2].trim());
找到++;
}
}
if (找到 === 0) print.log(" 未找到 Resumed 相关行,输出前3行:");
for (var di3 = 0; di3 < Math.min(3, 诊断行.length); di3++) {
print.log(" " + 诊断行[di3].trim());
}
} else {
print.log(" dumpsys activity activities 返回空!");
}
}
if (前台包名) {
print.log(" 是否在前台判断: " + (AdbUtil.是否在前台(前台包名) ? "是 ✓" : "否"));
}
print.log("✅ 演示2 完成");
// ===== 演示3:第三方应用列表 =====
倒计时("演示3 / 第三方应用列表");
print.log("【演示3】第三方应用列表(前5个)");
var 应用列表 = AdbUtil.列出第三方应用();
print.log(" 共 " + 应用列表.length + " 个第三方应用");
for (var i = 0; i < Math.min(5, 应用列表.length); i++) {
var 信息 = AdbUtil.获取应用信息(应用列表[i]);
print.log(" " + (i + 1) + ". " + 应用列表[i] + " v" + (信息.版本名 || "?"));
// 诊断:第一个应用版本为空时,打印 grep version 的原始输出
if (!信息.版本名 && i === 0) {
print.log(" [诊断] dumpsys package " + 应用列表[i] + " | grep version 输出:");
var 诊断pkg = 执行命令("dumpsys package " + 应用列表[i] + " | grep version", true);
if (诊断pkg && 诊断pkg.length > 0) {
var pkg行 = 诊断pkg.split("\n");
for (var dpk = 0; dpk < Math.min(5, pkg行.length); dpk++) {
print.log(" " + pkg行[dpk].trim());
}
} else {
print.log(" dumpsys package | grep version 返回空!");
}
}
}
print.log("✅ 演示3 完成");
// ===== 演示4:进程检查 =====
倒计时("演示4 / 进程检查");
print.log("【演示4】进程检查");
print.log(" 微信是否运行: " + (AdbUtil.进程是否存在("com.tencent.mm") ? "是 ✓" : "否"));
print.log(" 淘宝是否运行: " + (AdbUtil.进程是否存在("com.taobao.taobao") ? "是 ✓" : "否"));
print.log(" QQ是否运行: " + (AdbUtil.进程是否存在("com.tencent.mobileqq") ? "是 ✓" : "否"));
print.log(" 设置是否运行: " + (AdbUtil.进程是否存在("com.android.settings") ? "是 ✓" : "否"));
print.log("✅ 演示4 完成");
// ===== 演示5:网络诊断 =====
倒计时("演示5 / 网络诊断");
print.log("【演示5】网络诊断");
var ip = AdbUtil.获取WiFiIP();
print.log(" WiFi IP: " + (ip || "未连接 WiFi"));
print.log(" Ping 百度: ");
var ping结果 = AdbUtil.Ping("www.baidu.com", 3);
var ping行 = ping结果.split("\n");
var 统计行 = [];
for (var j = ping行.length - 1; j >= 0 && 统计行.length < 3; j--) {
if (ping行[j].trim()) 统计行.unshift(ping行[j].trim());
}
for (var k = 0; k < 统计行.length; k++) {
print.log(" " + 统计行[k]);
}
print.log("✅ 演示5 完成");
// ===== 演示6:文件操作 =====
倒计时("演示6 / 文件操作");
print.log("【演示6】文件操作");
AdbUtil.创建目录("/sdcard/aiwrok_test");
print.log(" ✓ 创建目录 /sdcard/aiwrok_test");
var 写入时间 = new Date().toLocaleString();
AdbUtil.写文件("/sdcard/aiwrok_test/test.txt", "AIWROK adb.exec 测试 " + 写入时间);
print.log(" ✓ 写入文件: AIWROK adb.exec 测试 " + 写入时间);
var 内容 = AdbUtil.读文件("/sdcard/aiwrok_test/test.txt");
print.log(" ✓ 读取文件: " + 内容);
var 大小 = AdbUtil.文件大小("/sdcard/aiwrok_test/test.txt");
print.log(" ✓ 文件大小: " + 大小 + " 字节");
// 测试追加写入
AdbUtil.追加写文件("/sdcard/aiwrok_test/test.txt", "——追加的第二行");
var 内容2 = AdbUtil.读文件("/sdcard/aiwrok_test/test.txt");
print.log(" ✓ 追加后内容: " + 内容2.replace(/\n/g, " | "));
// 测试列目录
var 目录内容 = AdbUtil.列目录("/sdcard/aiwrok_test/");
print.log(" ✓ 目录内容:");
var 目录行 = 目录内容.split("\n");
for (var di = 0; di < Math.min(5, 目录行.length); di++) {
if (目录行[di].trim()) print.log(" " + 目录行[di].trim());
}
// 测试复制文件
AdbUtil.复制文件("/sdcard/aiwrok_test/test.txt", "/sdcard/aiwrok_test/test_backup.txt");
print.log(" ✓ 复制文件 → test_backup.txt");
print.log("✅ 演示6 完成");
// ===== 演示7:截图 =====
倒计时("演示7 / 截图");
print.log("【演示7】截图");
var 截图路径 = "/sdcard/aiwrok_test/screenshot_" + Date.now() + ".png";
AdbUtil.截图(截图路径);
var 截图大小 = AdbUtil.文件大小(截图路径);
print.log(" 截图文件大小: " + 截图大小 + " 字节");
print.log("✅ 演示7 完成");
// ===== 演示8:屏幕超时 =====
倒计时("演示8 / 屏幕超时设置");
print.log("【演示8】屏幕超时");
var 超时 = AdbUtil.获取屏幕超时();
print.log(" 当前屏幕超时: " + (超时 || "获取失败") + " 毫秒");
if (超时) {
var 秒数 = Math.floor(parseInt(超时, 10) / 1000);
print.log(" 即: " + 秒数 + " 秒");
}
print.log("✅ 演示8 完成");
// ===== 演示9:输入模拟 =====
倒计时("演示9 / 输入模拟(Home/点击/滑动/按键)");
print.log("【演示9】输入模拟(真实执行)");
print.log(" [9.1] 按 Home 键回到桌面...");
AdbUtil.Home键();
sleep.second(1);
print.log(" ✓ 已按 Home 键");
var 回桌面后 = AdbUtil.获取前台包名();
print.log(" 当前前台: " + (回桌面后 || "未知"));
var 屏幕信息9 = AdbUtil.获取屏幕信息();
var 分辨率文本 = 屏幕信息9.分辨率 || "";
var 尺寸匹配 = 分辨率文本.match(/(\d+)x(\d+)/);
if (尺寸匹配) {
var 宽度 = parseInt(尺寸匹配[1], 10);
var 高度 = parseInt(尺寸匹配[2], 10);
var 中心X = Math.floor(宽度 / 2);
var 中心Y = Math.floor(高度 / 2);
print.log(" [9.2] 屏幕分辨率 " + 宽度 + "x" + 高度 + ",中心点 (" + 中心X + ", " + 中心Y + ")");
print.log(" [9.3] 点击屏幕中心...");
AdbUtil.点击(中心X, 中心Y);
sleep.millisecond(500);
print.log(" ✓ 已点击 (" + 中心X + ", " + 中心Y + ")");
print.log(" [9.4] 向上滑动...");
AdbUtil.滑动(中心X, Math.floor(高度 * 0.8), 中心X, Math.floor(高度 * 0.2), 300);
sleep.millisecond(500);
print.log(" ✓ 已向上滑动");
print.log(" [9.5] 下拉通知栏...");
AdbUtil.滑动(中心X, Math.floor(高度 * 0.1), 中心X, Math.floor(高度 * 0.5), 300);
sleep.second(1);
print.log(" ✓ 已下拉通知栏");
print.log(" [9.6] 收起通知栏...");
AdbUtil.滑动(中心X, Math.floor(高度 * 0.5), 中心X, Math.floor(高度 * 0.1), 300);
sleep.millisecond(500);
print.log(" ✓ 已收起通知栏");
} else {
print.log(" [9.2] 无法解析屏幕分辨率: " + 分辨率文本);
}
print.log(" [9.7] 按返回键...");
AdbUtil.返回键();
sleep.millisecond(500);
print.log(" ✓ 已按返回键");
print.log(" [9.8] 按音量减键...");
AdbUtil.按键(25);
sleep.millisecond(500);
print.log(" ✓ 已按音量减键");
print.log(" [9.9] 按音量加键恢复...");
AdbUtil.按键(24);
sleep.millisecond(500);
print.log(" ✓ 已按音量加键");
print.log("✅ 演示9 完成");
// ===== 演示10:应用管理 =====
倒计时("演示10 / 应用管理(安装检测/启动设置/截图)");
print.log("【演示10】应用管理(真实执行)");
print.log(" [10.1] 检查常见应用安装状态");
var 常见应用 = [
"com.tencent.mm", // 微信
"com.taobao.taobao", // 淘宝
"com.android.settings", // 系统设置
"com.tencent.mobileqq", // QQ
"com.eg.android.AlipayGphone" // 支付宝
];
for (var ai = 0; ai < 常见应用.length; ai++) {
var 已安装 = AdbUtil.应用是否安装(常见应用[ai]);
print.log(" " + 常见应用[ai] + ": " + (已安装 ? "已安装 ✓" : "未安装"));
}
print.log("\n [10.2] 获取已安装应用详细信息");
var 已安装应用 = null;
for (var bi = 0; bi < 常见应用.length; bi++) {
if (AdbUtil.应用是否安装(常见应用[bi])) {
已安装应用 = 常见应用[bi];
break;
}
}
if (已安装应用) {
var 详情 = AdbUtil.获取应用信息(已安装应用);
print.log(" 包名: " + 已安装应用);
print.log(" 版本名: " + (详情.版本名 || "未知"));
print.log(" 版本号: " + (详情.版本号 || "未知"));
print.log(" 安装路径: " + (详情.安装路径 || "未知"));
} else {
print.log(" 常见应用均未安装");
}
print.log("\n [10.3] 启动系统设置");
var 启动结果 = AdbUtil.启动Action("android.settings.SETTINGS");
sleep.second(2);
print.log(" 启动命令已执行: " + (启动结果 ? "✓" : "✗"));
var 设置前台 = AdbUtil.获取前台包名();
print.log(" 当前前台包名: " + (设置前台 || "未知"));
if (设置前台 && 设置前台.indexOf("settings") !== -1) {
print.log(" ✓ 系统设置已打开");
} else {
print.log(" (设置页面可能正在加载或设备不支持)");
}
var 设置Activity = AdbUtil.获取前台Activity();
print.log(" 当前前台Activity: " + (设置Activity || "未知"));
print.log("\n [10.4] 截图保存设置页面");
AdbUtil.截图("/sdcard/aiwrok_test/settings_page.png");
print.log(" [10.5] 检查设置进程状态");
var 设置运行 = AdbUtil.进程是否存在("com.android.settings");
if (!设置运行) 设置运行 = AdbUtil.进程是否存在("settings");
print.log(" 设置进程运行中: " + (设置运行 ? "是 ✓" : "否"));
print.log(" [10.6] 按 Home 键回到桌面");
AdbUtil.Home键();
sleep.second(1);
var 回桌面后2 = AdbUtil.获取前台包名();
print.log(" 当前前台: " + (回桌面后2 || "未知"));
print.log("✅ 演示10 完成");
// ===== 演示11:存储与CPU信息 =====
倒计时("演示11 / 存储与CPU信息");
print.log("【演示11】存储与CPU信息");
var 存储 = AdbUtil.获取存储信息();
print.log(" 存储信息:");
var 存储行 = 存储.split("\n");
for (var si = 0; si < 存储行.length; si++) {
if (存储行[si].trim()) print.log(" " + 存储行[si].trim());
}
print.log("\n CPU 占用 TOP 进程:");
var cpu = AdbUtil.获取CPU占用();
var cpu行 = cpu.split("\n");
for (var ci = 0; ci < Math.min(8, cpu行.length); ci++) {
if (cpu行[ci].trim()) print.log(" " + cpu行[ci].trim());
}
print.log("✅ 演示11 完成");
// ===== 演示12:网络完整诊断 =====
倒计时("演示12 / 网络完整诊断");
print.log("【演示12】网络完整诊断");
print.log(" WiFi IP: " + (AdbUtil.获取WiFiIP() || "未连接"));
var 路由 = AdbUtil.获取路由表();
print.log(" 路由表:");
var 路由行 = 路由.split("\n");
for (var ri = 0; ri < Math.min(3, 路由行.length); ri++) {
if (路由行[ri].trim()) print.log(" " + 路由行[ri].trim());
}
print.log(" 网络接口信息:");
var 接口 = AdbUtil.获取网络接口();
var 接口行 = 接口.split("\n");
for (var ni = 0; ni < Math.min(5, 接口行.length); ni++) {
if (接口行[ni].trim()) print.log(" " + 接口行[ni].trim());
}
print.log("✅ 演示12 完成");
// =============================================================================
// 速查表
// =============================================================================
print.log("\n========== AdbUtil 方法速查表 ==========\n");
print.log("设备信息:");
print.log(" AdbUtil.获取设备信息() → {型号,品牌,安卓版本,SDK版本,制造商,序列号}");
print.log(" AdbUtil.获取屏幕信息() → {分辨率,密度}");
print.log(" AdbUtil.获取电池信息() → {电量,温度,状态,技术}");
print.log(" AdbUtil.获取内存信息() → MemTotal/MemFree/MemAvailable");
print.log(" AdbUtil.获取存储信息() → df 输出");
print.log("");
print.log("应用管理:");
print.log(" AdbUtil.列出第三方应用() → [包名数组]");
print.log(" AdbUtil.应用是否安装(包名) → true/false");
print.log(" AdbUtil.启动应用(包名) → true/false");
print.log(" AdbUtil.停止应用(包名) → true/false");
print.log(" AdbUtil.安装应用(路径,覆盖) → true/false");
print.log(" AdbUtil.卸载应用(包名) → true/false");
print.log(" AdbUtil.获取应用信息(包名) → {版本名,版本号,安装路径}");
print.log("");
print.log("文件操作:");
print.log(" AdbUtil.列目录(路径) → ls 输出");
print.log(" AdbUtil.读文件(路径) → 文件内容");
print.log(" AdbUtil.写文件(路径,内容) → true/false");
print.log(" AdbUtil.追加写文件(路径,内容) → true/false");
print.log(" AdbUtil.复制文件(源,目标) → true/false");
print.log(" AdbUtil.创建目录(路径) → true/false");
print.log(" AdbUtil.删除(路径) → true/false");
print.log(" AdbUtil.文件大小(路径) → 字节数");
print.log("");
print.log("输入模拟:");
print.log(" AdbUtil.点击(x, y) → true/false");
print.log(" AdbUtil.滑动(x1,y1,x2,y2,时长) → true/false");
print.log(" AdbUtil.长按(x, y, 时长) → true/false");
print.log(" AdbUtil.输入文字(文字) → true/false (仅ASCII)");
print.log(" AdbUtil.按键(键码) → true/false");
print.log(" AdbUtil.返回键() → 模拟返回");
print.log(" AdbUtil.Home键() → 模拟Home");
print.log("");
print.log("前台检测+进程:");
print.log(" AdbUtil.获取前台包名() → 'com.xxx.xxx'");
print.log(" AdbUtil.获取前台Activity() → 'com.xxx/.Activity'");
print.log(" AdbUtil.是否在前台(包名) → true/false");
print.log(" AdbUtil.进程是否存在(包名) → true/false");
print.log(" AdbUtil.获取CPU占用() → top 输出");
print.log(" AdbUtil.杀死进程(pid,root) → true/false");
print.log("");
print.log("截图+网络:");
print.log(" AdbUtil.截图(路径) → true/false");
print.log(" AdbUtil.Ping(地址,次数) → ping 输出");
print.log(" AdbUtil.获取WiFiIP() → '192.168.x.x'");
print.log(" AdbUtil.获取网络接口() → ip addr 输出");
print.log(" AdbUtil.获取路由表() → ip route 输出");
print.log("");
print.log("系统设置:");
print.log(" AdbUtil.获取设置(命名空间,键名,root) → 设置值");
print.log(" AdbUtil.设置值(命名空间,键名,值,root) → true/false");
print.log(" AdbUtil.获取屏幕超时() → 毫秒数");
print.log(" AdbUtil.设置屏幕超时(毫秒) → true/false");
print.log("\n✅ adb.exec() 实用工具库执行完毕");
print.log("提示:将本文件内容复制到你的项目中,即可通过 AdbUtil.方法名() 直接调用");
复制代码
欢迎光临 自动发帖软件 (http://www.fatiegongju.com/)
Powered by Discuz! X3.2