更多信息请参阅 JavaScript Modules。
如何使用
简介:
本示例演示如何在多设备批量执行流程中使用 ArrayOutput 收集每台设备的执行结果,并通过 ArrayOutputReturn 进行统一读取与分析。示例涵盖结果结构、常用访问方式、错误判断与调试技巧,可直接复制运行并应用于实际项目。
运行前:
>> sigmaLoad("TestArrayOutput.js");
源代码
/**
* ArrayOutput 全功能示例:多设备批量执行 + 详细说明(可直接复制运行)
*
* 你将学到/看到:
* 1) ArrayOutput:用于“收集”每台设备的执行结果(value + error)
* 2) ArrayOutputReturn:用于“读取/查询”结果(只读包装器)
* 3) global.showOutputFlag:
* - 开启后 getReturn() 会自动 print 一份结构化表格
* - 并且把最新的 ArrayOutputReturn 赋值给 global.ao(全局调试别名)
* 4) ret.get() 的三种形态:
* - ret.get() => 返回完整 records 数组(每条包含 name/object/id/value/error)
* - ret.get(device) => 返回该 device 的 value
* - ret.get([device...]) => 返回与输入数组等长的 value 数组(顺序对齐输入)
* 5) 动态 helpers(objects/values/errors/ids/names):
* - 无参:返回整列数组
* - 带 1 个参数:返回某个对象对应字段的单值
* 6) success():所有 error 都为空则为 true
* 7) lastError():返回最后一个 error 不为空的条目(从尾到头扫描)
* 8) findObj():
* - 既支持传 device 对象
* - 也支持传 String(device)(即 id)
*
* 注意:
* - 下面的 runFlow() 用的是你项目里常见的 Total Control API(runApp/isAppForeground/click2/inputText...)
* - 如果某些 API 在你的环境中名字不同,替换掉即可,不影响 ArrayOutput 的示例逻辑
*/
var { getDevices, Device } = require("sigma/device");
// ===================== 配置:示例要操控的 App 与动作 =====================
var TARGET_PKG = "com.sigma_rt.sigmatestapp";
var SEARCH_TEXT = "500";
var WAIT_LAUNCH_MS = 1200;
var SEARCH_X = 0.5352;
var SEARCH_Y = 0.135;
// ===================== 工具函数:设备名称/日志/按键 =====================
function devName(d) {
// 兼容不同设备对象字段:name/getName/SN
return d.name || (d.getName && d.getName()) || d.SN || "UnknownDevice";
}
function logDev(d, s) {
print("[" + devName(d) + "] " + s);
}
function press(d, keyConst) {
// Total Control 常见方式:send(KEY_*, STATE_PRESS)
var ret = d.send(keyConst, tcConst.STATE_PRESS);
if (ret !== 0) throw new Error("send failed: " + lastError());
}
/**
* step():一个简单的“步骤包装器”
* - 作用:把 try/catch + 错误字符串化统一起来,便于流程代码更清晰
* - 返回:{ ok: true, ret: any } 或 { ok: false, err: string }
*/
function step(label, fn) {
try {
var r = fn();
return { ok: true, ret: r };
} catch (e) {
return { ok: false, err: String(e && e.message ? e.message : e) };
}
}
// ===================== 单设备流程:成功返回 value(对象),失败 throw(由外层收集 error) =====================
/**
* runFlow(d) 的返回值会作为 ArrayOutput.add(d, value) 的 value。
* 如果 runFlow 抛异常,外层 catch 后会 out.add(d, null, errorText)。
*/
function runFlow(d) {
// 这是最终要“返回并收集”的 value(结构化更利于后续分析)
var result = {
ok: false,
step: "", // 记录失败/结束所在步骤
fg: "", // 前台包名(成功时)
act: "", // activity(成功时)
};
logDev(d, "=== DEVICE BEGIN ===");
// 1) 启动 App
var s1 = step("runApp", function () {
var r = d.runApp(TARGET_PKG);
if (r !== 0) throw new Error(lastError());
sleep(WAIT_LAUNCH_MS);
return 0;
});
if (!s1.ok) {
result.step = "runApp";
throw new Error("runApp failed: " + s1.err);
}
// 2) 校验前台 + 读取前台信息
var s2 = step("foregroundCheck", function () {
var r = d.isAppForeground(TARGET_PKG);
if (r !== 0) throw new Error("not foreground: " + lastError());
result.fg = d.getForegroundApp() || "";
result.act = d.getActivity() || "";
return 0;
});
if (!s2.ok) {
result.step = "foregroundCheck";
throw new Error("foregroundCheck failed: " + s2.err);
}
// 3) 点击搜索框
var s3 = step("clickSearch", function () {
var r = d.click2(SEARCH_X, SEARCH_Y, { dx: 0.08, dy: 0.04 });
if (r !== 0) throw new Error(lastError());
sleep(250);
return 0;
});
if (!s3.ok) {
result.step = "clickSearch";
throw new Error("clickSearch failed: " + s3.err);
}
// 4) 输入并回车
var s4 = step("inputText", function () {
var r = d.inputText(SEARCH_TEXT + "\n");
if (r !== 0) throw new Error("inputText failed: " + lastError());
sleep(600);
return 0;
});
if (!s4.ok) {
result.step = "inputText";
throw new Error("inputText failed: " + s4.err);
}
// 5) 翻页(示例:失败不致命,这里不 throw,仅演示可以继续)
step("paging", function () {
d.pgDn();
sleep(200);
d.shiftPgDn();
sleep(300);
return 0;
});
// 6) 返回/主页
var s6 = step("backHome", function () {
press(d, tcConst.KEY_BACK);
sleep(200);
press(d, tcConst.KEY_HOME);
sleep(300);
return 0;
});
if (!s6.ok) {
result.step = "backHome";
throw new Error("backHome failed: " + s6.err);
}
// 7) 关闭(失败不致命)
step("closeApp", function () {
d.closeApp(TARGET_PKG);
return 0;
});
result.ok = true;
result.step = "done";
logDev(d, "=== DEVICE END (OK) ===");
return result;
}
// ===================== 主入口:收集 + 返回包装器 + 全功能读取演示 =====================
function main() {
/**
* showOutputFlag 的意义:
* - out.getReturn() 时模块内部会打印一份简化表:
* [{name, object: id, value, error}, ...]
* - 并把 global.ao 设置为最新返回对象(方便你在控制台直接 ao.values() 查看)
*/
global.showOutputFlag = true;
if (Device.connectAll) Device.connectAll();
var devices = getDevices();
if (!devices || devices.length === 0) {
print("No selected devices. Please select devices first.");
return;
}
print("Selected devices: " + devices.length);
// 1) 创建收集器
var out = new ArrayOutput();
// 2) 批量执行:每台设备产生 value 或 error
for (var i = 0; i < devices.length; i++) {
var d = devices[i];
print("\n==============================");
print("RUN " + (i + 1) + "/" + devices.length + " : " + devName(d));
print("==============================");
try {
// 成功:value 是结构化对象(推荐)
var value = runFlow(d);
out.add(d, value); // error 省略默认 null
} catch (e) {
// 失败:value 为 null,error 为字符串
out.add(d, null, String(e && e.message ? e.message : e));
}
}
// 3) 得到只读返回对象(核心)
var ret = out.getReturn();
// 4) 验证全局别名
print("\n-- global alias check --");
print("ret === global.ao ? " + (ret === global.ao));
// =========================================================
// A. 状态类 API:toString / success / lastError
// =========================================================
print("\n-- status APIs --");
print(ret.toString()); // "ArrayOutputReturn: N elements"
print("success() = " + ret.success()); // 全部无 error 才 true
var lastErr = ret.lastError(); // {object, id, error} 或 undefined
if (lastErr) {
print("lastError.id=" + lastErr.id);
print("lastError.error=" + lastErr.error);
} else {
print("lastError() = undefined (no errors)");
}
// =========================================================
// B. get() 三种形态(最重要的查询入口)
// =========================================================
print("\n-- get() forms --");
// 1) ret.get():取全部 records(每条都包含:name/object/id/value/error)
var all = ret.get();
print("get() records length = " + all.length);
// all[0] 示例结构:
// {
// name: "DeviceName",
// object: <deviceObject>,
// id: "String(deviceObject)",
// value: <你的结果对象或任意值>,
// error: <错误字符串或 null>
// }
// 2) ret.get(device):取单设备 value(不是 record)
var d0 = devices[0];
print("get(device0) value = " + JSON.stringify(ret.get(d0)));
// 3) ret.get([device...]):批量取 value(顺序对齐输入数组)
var pick = devices.slice(0, Math.min(3, devices.length));
print("get([device0..]) values = " + JSON.stringify(ret.get(pick)));
// =========================================================
// C. 动态 helpers:objects/values/errors/ids/names
// =========================================================
print("\n-- helpers (no args) --");
// 无参:整列数组
// 注意:objects() 返回的数组是设备对象本体;打印时可能显示为 [object ...]
print("objects() = " + ret.objects());
print("values() = " + JSON.stringify(ret.values()));
print("errors() = " + JSON.stringify(ret.errors()));
print("ids() = " + JSON.stringify(ret.ids()));
print("names() = " + JSON.stringify(ret.names()));
print("\n-- helpers (single target) --");
// 单参数:取某个设备的一项字段
print("values(device0) = " + JSON.stringify(ret.values(d0)));
print("errors(device0) = " + JSON.stringify(ret.errors(d0)));
print("ids(device0) = " + JSON.stringify(ret.ids(d0)));
print("names(device0) = " + JSON.stringify(ret.names(d0)));
print("objects(device0)= " + ret.objects(d0));
// =========================================================
// D. findObj:定位索引(object / string id 两种方式)
// =========================================================
print("\n-- findObj() --");
// 1) 传对象:通过 identity 或 String(obj) 匹配
var idxByObj = ret.findObj(d0);
print("findObj(device0) = " + idxByObj);
// 2) 传字符串:按 String(this.output[i].object) 匹配
// 也就是 add() 时存的 id = String(obj)
var id0 = String(d0);
var idxById = ret.findObj(id0);
print("findObj(String(device0)) = " + idxById + ' (id="' + id0 + '")');
// =========================================================
// E. 全局 ao:调试快捷入口(ret 的同一个对象)
// =========================================================
print("\n-- global ao usage --");
print("ao.values() = " + JSON.stringify(ao.values()));
print("ao.errors() = " + JSON.stringify(ao.errors()));
print("ao.success() = " + ao.success());
// =========================================================
// F. 常见实战:做一份可读性更强的汇总输出
// =========================================================
print("\n===== SUMMARY (computed) =====");
var names = ret.names();
var errs = ret.errors();
var vals = ret.values();
var okCount = 0;
for (var k = 0; k < names.length; k++) {
if (!errs[k]) {
okCount++;
print("[" + names[k] + "] OK step=" + (vals[k] && vals[k].step));
} else {
print("[" + names[k] + "] FAIL err=" + errs[k]);
}
}
print("Success: " + okCount + " / " + names.length);
/**
* 额外提示(常见用法建议):
* - 建议 value 保存结构化对象(如 {ok, step, fg, act, ...}),便于后续统计与定位
* - 建议 error 保存 String(err)
* - 你可以在失败时把更多信息塞进 error 文本或 value(例如截图路径、耗时、关键参数)
*/
}
main();
运行结果
Selected devices: 3
==============================
RUN 1/3 : HONOR-HLK-AL00
==============================
[HONOR-HLK-AL00] === DEVICE BEGIN ===
[HONOR-HLK-AL00] === DEVICE END (OK) ===
==============================
RUN 2/3 : HONOR-HLK-AL00
==============================
[HONOR-HLK-AL00] === DEVICE BEGIN ===
[HONOR-HLK-AL00] === DEVICE END (OK) ===
==============================
RUN 3/3 : HONOR-HLK-AL00
==============================
[HONOR-HLK-AL00] === DEVICE BEGIN ===
[HONOR-HLK-AL00] === DEVICE END (OK) ===
{name: 'HONOR-HLK-AL00', object: 'device@1658225331', value: {ok: true, step: 'done', fg: 'com.sigma_rt.sigmatestapp', act: 'com.huawei.android.launcher/.unihome.UniHomeLauncher'}, error: null},{name: 'HONOR-HLK-AL00', object: 'device@403850225', value: {ok: true, step: 'done', fg: 'com.sigma_rt.sigmatestapp', act: 'com.huawei.android.launcher/.unihome.UniHomeLauncher'}, error: null},{name: 'HONOR-HLK-AL00', object: 'device@2081074872', value: {ok: true, step: 'done', fg: 'com.sigma_rt.sigmatestapp', act: 'com.sigma_rt.sigmatestapp/.MainActivity'}, error: null}
-- global alias check --
ret === global.ao ? true
aoAlias === global.ao ? false
-- status APIs --
ArrayOutputReturn: 3 elements
success() = true
lastError() = undefined (no errors)
-- get() forms --
get() records length = 3
get(device0) value = {"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"}
get([device0..]) values = [{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.sigma_rt.sigmatestapp/.MainActivity"}]
-- helpers (no args) --
objects() = device@1658225331,device@403850225,device@2081074872
values() = [{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.sigma_rt.sigmatestapp/.MainActivity"}]
errors() = [null,null,null]
ids() = ["device@1658225331","device@403850225","device@2081074872"]
names() = ["HONOR-HLK-AL00","HONOR-HLK-AL00","HONOR-HLK-AL00"]
-- helpers (single target) --
values(device0) = {"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"}
errors(device0) = null
ids(device0) = "device@1658225331"
names(device0) = "HONOR-HLK-AL00"
objects(device0)= device@1658225331
-- findObj() --
findObj(device0) = 0
findObj(String(device0)) = 0 (id="device@1658225331")
-- global ao usage --
ao.values() = [{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.huawei.android.launcher/.unihome.UniHomeLauncher"},{"ok":true,"step":"done","fg":"com.sigma_rt.sigmatestapp","act":"com.sigma_rt.sigmatestapp/.MainActivity"}]
ao.errors() = [null,null,null]
ao.success() = true
===== SUMMARY (computed) =====
[HONOR-HLK-AL00] OK step=done
[HONOR-HLK-AL00] OK step=done
[HONOR-HLK-AL00] OK step=done
Success: 3 / 3