import { createDriver } from '../drivers/factory'; import * as fs from 'fs'; (async () => { const d = createDriver(); await d.createSession(); const KW = process.env.LIGHT_CARD || 'Permanent Outdoor Lights'; try { await d.dismissPopupIfPresent(); await d.goBackToHomepage(); await new Promise((r) => setTimeout(r, 1000)); let el: string | null = null; for (let i = 0; i < 10; i++) { el = await d.findElementRaw('-android uiautomator', `new UiSelector().textContains("${KW}")`).catch(() => null); if (el) break; await d.swipe(540, 1500, 540, 700, 0.4).catch(() => {}); await new Promise((r) => setTimeout(r, 800)); } if (!el) throw new Error('找不到灯卡片'); const rect = await d.getElementRect(el); console.log(`卡片文本 rect=(${rect.x},${rect.y}) ${rect.width}x${rect.height}`); await d.tap(rect.x + rect.width / 2, rect.y + rect.height / 2); await new Promise((r) => setTimeout(r, 2500)); const size = await d.getWindowSize(); console.log(`屏幕 ${size.width}x${size.height}`); const src = await d.getSource(); const texts = [...new Set(Array.from(src.matchAll(/text="([^"]+)"/g)).map((m) => m[1]).filter((t) => t.trim()))]; console.log('TEXTS=' + JSON.stringify(texts)); // clickable 节点 const clk = Array.from(src.matchAll(/clickable="true"[^>]*?bounds="(\[\d+,\d+\]\[\d+,\d+\])"/g)).map((m) => m[1]); console.log('CLICKABLE=' + JSON.stringify(clk.slice(0, 30))); // 滑条类节点(SeekBar/ProgressBar/Slider) — 找 class 含 SeekBar/Slider 或 scrollable const sliders = Array.from(src.matchAll(/<[^>]*class="([^"]*(?:SeekBar|Slider|ProgressBar)[^"]*)"[^>]*bounds="(\[\d+,\d+\]\[\d+,\d+\])"[^>]*>/g)).map((m) => `${m[1]} ${m[2]}`); console.log('SLIDERS=' + JSON.stringify(sliders)); // 浮层下半区(y>1300)所有"宽"节点(width>400):RN 自绘滑条候选 const wide: string[] = []; for (const m of src.matchAll(/<[^>]*class="([^"]+)"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*>/g)) { const [cls, x1, y1, x2, y2] = [m[1], +m[2], +m[3], +m[4], +m[5]]; const w = x2 - x1, h = y2 - y1; if (y1 > 1300 && w > 400 && h < 300) wide.push(`${cls.split('.').pop()} [${x1},${y1}][${x2},${y2}] w${w}h${h}`); } console.log('WIDE_NODES=' + JSON.stringify(wide.slice(0, 20))); // 开灯后再看滑条填充条:点电源 → dump 滑条 y 区间(1620-1850)内所有节点(找蓝色填充 View 的右边缘=亮度) await d.tap(540, 1455); // 电源键 await new Promise((r) => setTimeout(r, 3500)); const src2 = await d.getSource(); const inTrack: string[] = []; for (const m of src2.matchAll(/<[^>]*class="([^"]+)"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*>/g)) { const [cls, x1, y1, x2, y2] = [m[1], +m[2], +m[3], +m[4], +m[5]]; if (y1 >= 1600 && y2 <= 1860 && x2 - x1 > 30) inTrack.push(`${cls.split('.').pop()} [${x1},${y1}][${x2},${y2}] w${x2 - x1}`); } const st = [...new Set(Array.from(src2.matchAll(/text="([^"]+)"/g)).map((m) => m[1]))].slice(0, 8); console.log('AFTER_ON_TEXTS=' + JSON.stringify(st)); console.log('TRACK_NODES=' + JSON.stringify(inTrack.slice(0, 15))); const ss = await d.screenshot(); fs.writeFileSync('/tmp/light_popup.png', Buffer.from(ss, 'base64')); console.log('截图: /tmp/light_popup.png'); } catch (e: any) { console.error('探针失败:', e.message); } finally { await d.destroySession(); } })();