/** * probe-dump.js — 把当前屏幕的控件树完整 dump 到一个文本文件 * * 为什么不用 `uiautomator dump`:TikTok 的页面一直在动(视频、动画), * uiautomator 等不到 idle state 就直接失败(实测 "could not get idle state")。 * 而 AutoX 的无障碍读取不需要 idle,且**与引擎最终用的是同一套读取路径** —— * 探针看到的和引擎将来看到的完全一致。 * * 用法:adb 启动本脚本,几秒后读 /sdcard/tiktok_app/probe-dump.txt */ var OUT = "/sdcard/tiktok_app/probe-dump.txt"; function clean(v) { if (v === null || v === undefined) { return ""; } return String(v).replace(/[\u200b-\u200f\u202a-\u202e\ufeff]/g, "").replace(/\s+/g, " ").replace(/^\s+|\s+$/g, ""); } function collect() { var lines = []; var start = auto.root; if (!start) { return ["root=null"]; } var stack = [{ node: start, depth: 0 }]; var count = 0; while (stack.length > 0 && count < 2000) { var item = stack.pop(); var node = item.node; if (!node) { continue; } count += 1; var box = null; var text = "", desc = "", cls = "", rid = "", clickable = false, scrollable = false, editable = false, selected = false; try { box = node.bounds(); } catch (e) { box = null; } try { text = clean(node.text()); } catch (e) { } try { desc = clean(node.desc()); } catch (e) { } try { cls = String(node.className()); } catch (e) { } try { rid = String(node.id() || ""); } catch (e) { } try { clickable = node.clickable() === true; } catch (e) { } try { scrollable = node.scrollable() === true; } catch (e) { } try { editable = node.className() === "android.widget.EditText"; } catch (e) { } try { selected = node.selected() === true; } catch (e) { } var visible = false; try { visible = node.isVisibleToUser() === true; } catch (e) { visible = true; } if (visible && (text !== "" || desc !== "" || clickable || scrollable)) { var short = cls.split(".").pop(); var shortId = rid.indexOf("/") >= 0 ? rid.split("/").pop() : rid; lines.push([ item.depth, short, shortId, box ? ("[" + box.left + "," + box.top + "][" + box.right + "," + box.bottom + "]") : "[]", clickable ? "CLK" : "-", scrollable ? "SCR" : "-", editable ? "EDT" : "-", selected ? "SEL" : "-", JSON.stringify(text), JSON.stringify(desc) ].join(" ")); } var childCount = 0; try { childCount = node.childCount(); } catch (e) { childCount = 0; } for (var i = childCount - 1; i >= 0; i -= 1) { try { stack.push({ node: node.child(i), depth: item.depth + 1 }); } catch (e) { } } } lines.unshift("total=" + count + " screen=" + device.width + "x" + device.height + " pkg=" + (auto.root ? auto.root.packageName() : "?")); return lines; } var lines = collect(); files.ensureDir("/sdcard/tiktok_app/"); files.write(OUT, lines.join("\n") + "\n"); console.log("probe written: " + OUT + " lines=" + lines.length);