@astur-mobile/core 0.5.0-beta.3 → 0.5.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flutter/network.d.ts +34 -0
- package/dist/flutter/network.d.ts.map +1 -0
- package/dist/flutter/network.js +121 -0
- package/dist/flutter/network.js.map +1 -0
- package/dist/flutter/vmService.d.ts +170 -0
- package/dist/flutter/vmService.d.ts.map +1 -0
- package/dist/flutter/vmService.js +630 -0
- package/dist/flutter/vmService.js.map +1 -0
- package/dist/image.d.ts +42 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +87 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/keyboard.d.ts +11 -0
- package/dist/keyboard.d.ts.map +1 -1
- package/dist/keyboard.js +13 -0
- package/dist/keyboard.js.map +1 -1
- package/dist/locator.d.ts +39 -0
- package/dist/locator.d.ts.map +1 -1
- package/dist/locator.js +77 -0
- package/dist/locator.js.map +1 -1
- package/dist/reactNative/network.d.ts +140 -0
- package/dist/reactNative/network.d.ts.map +1 -0
- package/dist/reactNative/network.js +382 -0
- package/dist/reactNative/network.js.map +1 -0
- package/dist/session.d.ts +41 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +48 -3
- package/dist/session.js.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import { AsturError } from '../errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reads a running Flutter app's UI through the Dart VM service.
|
|
4
|
+
*
|
|
5
|
+
* On Android, Flutter does not publish its widget tree to the OS accessibility
|
|
6
|
+
* layer, so the UIAutomator path sees an opaque FlutterView. Instead we evaluate
|
|
7
|
+
* a one-shot Dart walk of the element tree on-device, which returns every node's
|
|
8
|
+
* `Semantics(identifier)` (the same ids the app exposes for iOS), its text, and
|
|
9
|
+
* its GLOBAL bounds in physical pixels via `renderObject.localToGlobal()`.
|
|
10
|
+
*
|
|
11
|
+
* Evaluating source requires the Dart expression compiler, which is attached
|
|
12
|
+
* only when the app is launched through the Flutter tool (`flutter run`/`attach`)
|
|
13
|
+
* — see {@link FlutterProcess}.
|
|
14
|
+
*/
|
|
15
|
+
// Field separator (SOH) between columns; rows are newline-separated. Neither
|
|
16
|
+
// character can appear in widget ids/text/types, so parsing is unambiguous.
|
|
17
|
+
const SEP = '';
|
|
18
|
+
// Single-line Dart expression (the debug expression compiler rejects multi-line
|
|
19
|
+
// bodies). Walks the element tree depth-first and emits one row per node that
|
|
20
|
+
// carries an identifier, text, or label and has laid-out bounds.
|
|
21
|
+
//
|
|
22
|
+
// It skips subtrees that aren't actually painted so the tree matches what's on
|
|
23
|
+
// screen. This matters most for IndexedStack (the common "keep every tab
|
|
24
|
+
// mounted" pattern): it wraps every inactive child in an Offstage/Visibility so
|
|
25
|
+
// only the selected screen is shown. Skipping Offstage / Visibility(false) /
|
|
26
|
+
// Opacity(0) subtrees drops those inactive screens (and e.g. a closed drawer's
|
|
27
|
+
// backdrop) — otherwise every screen's widgets show up at once, overlapping and
|
|
28
|
+
// mostly not interactable. Only nodes actually on screen are emitted.
|
|
29
|
+
const EXTRACT_EXPR = '(){' +
|
|
30
|
+
'final sb=StringBuffer();' +
|
|
31
|
+
'final view=WidgetsBinding.instance.platformDispatcher.views.first;' +
|
|
32
|
+
'final dpr=view.devicePixelRatio;final sw=view.physicalSize.width;final sh=view.physicalSize.height;' +
|
|
33
|
+
// `cnt` assigns each emitted node a sequential id; `parent` threads the nearest
|
|
34
|
+
// emitted ancestor's id down the walk so the flat output can be rebuilt into a
|
|
35
|
+
// tree. Levels that don't emit (no id/text/label) are transparent — their
|
|
36
|
+
// children attach to the same ancestor — so geometry that reads a card's
|
|
37
|
+
// subtree (e.g. counters under a tap-lab card) matches the native nested tree.
|
|
38
|
+
'int cnt=0;' +
|
|
39
|
+
'void visit(Element el,int parent){' +
|
|
40
|
+
'final wd=el.widget;' +
|
|
41
|
+
'if(wd is Offstage && wd.offstage)return;' +
|
|
42
|
+
'if(wd is Visibility && !wd.visible)return;' +
|
|
43
|
+
'if(wd is Opacity && wd.opacity==0.0)return;' +
|
|
44
|
+
'final ro=el.renderObject;' +
|
|
45
|
+
'String? sid;String? lbl;String? txt;' +
|
|
46
|
+
'int self=parent;' +
|
|
47
|
+
'if(wd is Semantics){final p=wd.properties;if(p.identifier!=null)sid=p.identifier;if(p.label!=null)lbl=p.label;}' +
|
|
48
|
+
'if(wd is Text && wd.data!=null)txt=wd.data;' +
|
|
49
|
+
'if((sid!=null||txt!=null||lbl!=null) && ro is RenderBox && ro.attached && ro.hasSize){' +
|
|
50
|
+
'final o=ro.localToGlobal(Offset.zero);' +
|
|
51
|
+
'if(o.dx.isFinite && o.dy.isFinite){' +
|
|
52
|
+
'final x=(o.dx*dpr).round();final y=(o.dy*dpr).round();final w=(ro.size.width*dpr).round();final h=(ro.size.height*dpr).round();' +
|
|
53
|
+
'final on=(w>0 && h>0 && x+w>0 && y+h>0 && x<sw && y<sh);' +
|
|
54
|
+
'if(on){' +
|
|
55
|
+
'self=++cnt;' +
|
|
56
|
+
// An id-bearing node that directly wraps a text field (AsturId/Semantics around
|
|
57
|
+
// a TextField -> EditableText) is reported as "TextField" so the inspector
|
|
58
|
+
// recognises it as fillable. The search stops at nested id-bearing Semantics so
|
|
59
|
+
// a container (e.g. screen-login) that merely *contains* inputs isn't flagged.
|
|
60
|
+
'String kind=wd.runtimeType.toString();String val="";' +
|
|
61
|
+
// Walk into an id-bearing node to (a) classify it as a text field and (b) read
|
|
62
|
+
// its value. A Material TextField exposes both the typed text (controller.text)
|
|
63
|
+
// and, when empty, its placeholder (decoration.hintText) — mirroring Android's
|
|
64
|
+
// native behaviour where an empty EditText reports its hint as text, so
|
|
65
|
+
// toHaveValue works the same on both builds. EditableText is the universal
|
|
66
|
+
// fallback (every field type embeds one) for the typed value.
|
|
67
|
+
'if(sid!=null){bool ed=false;void ck(Element c){if(ed)return;final cw=c.widget;if(cw is Semantics && cw.properties.identifier!=null)return;if(cw is TextField){final t=cw.controller?.text;final hint=cw.decoration?.hintText;val=(t!=null && t.isNotEmpty)?t:(hint??"");ed=true;return;}if(cw is EditableText){val=cw.controller.text;ed=true;return;}c.visitChildren(ck);}el.visitChildren(ck);if(ed)kind="TextField";}' +
|
|
68
|
+
'sb.write(self.toString());sb.writeCharCode(1);sb.write(parent.toString());sb.writeCharCode(1);' +
|
|
69
|
+
'sb.write(sid??"");sb.writeCharCode(1);sb.write(txt??"");sb.writeCharCode(1);sb.write(lbl??"");sb.writeCharCode(1);' +
|
|
70
|
+
'sb.write(kind);sb.writeCharCode(1);' +
|
|
71
|
+
'sb.write(x.toString());sb.writeCharCode(1);sb.write(y.toString());sb.writeCharCode(1);' +
|
|
72
|
+
'sb.write(w.toString());sb.writeCharCode(1);sb.write(h.toString());sb.writeCharCode(1);sb.write("1");sb.writeCharCode(1);sb.write(val);sb.writeCharCode(10);' +
|
|
73
|
+
'}' +
|
|
74
|
+
'}}' +
|
|
75
|
+
'el.visitChildren((c){visit(c,self);});' +
|
|
76
|
+
'}' +
|
|
77
|
+
'visit(WidgetsBinding.instance.rootElement!,0);' +
|
|
78
|
+
'return sb.toString();' +
|
|
79
|
+
'}()';
|
|
80
|
+
// Readiness probe: reports "<idle>:<w>:<h>" where idle is 1 once a frame has
|
|
81
|
+
// fully completed (scheduler back to idle, root element attached) and w/h is the
|
|
82
|
+
// physical screen size. The physical size becomes non-zero BEFORE the first
|
|
83
|
+
// layout pass finishes, so gating on size alone yields render objects with zero
|
|
84
|
+
// bounds; waiting for an idle (completed) frame guarantees the tree is laid out.
|
|
85
|
+
// It only reads scalars (no tree walk), so it is safe to evaluate mid-build —
|
|
86
|
+
// unlike EXTRACT_EXPR, which can hit Flutter's build lock.
|
|
87
|
+
const READY_EXPR = '(){final r=WidgetsBinding.instance.rootElement;' +
|
|
88
|
+
'final v=WidgetsBinding.instance.platformDispatcher.views.first;' +
|
|
89
|
+
'final w=v.physicalSize.width.round();final h=v.physicalSize.height.round();' +
|
|
90
|
+
'final idle=(r!=null && WidgetsBinding.instance.schedulerPhase.name=="idle")?1:0;' +
|
|
91
|
+
'return idle.toString()+":"+w.toString()+":"+h.toString();}()';
|
|
92
|
+
// Clears the Flutter primary focus, which unfocuses the active text field and
|
|
93
|
+
// asks the engine to hide the soft keyboard. This is the deterministic way to
|
|
94
|
+
// dismiss the IME on the no-agent driver: unlike a Back press, it can never pop
|
|
95
|
+
// a route or background the app, so the widget tree stays intact afterwards.
|
|
96
|
+
const UNFOCUS_EXPR = '(){FocusManager.instance.primaryFocus?.unfocus();return "1";}()';
|
|
97
|
+
export class FlutterVmService {
|
|
98
|
+
ws;
|
|
99
|
+
nextId = 1;
|
|
100
|
+
pending = new Map();
|
|
101
|
+
isolateId;
|
|
102
|
+
rootLibId;
|
|
103
|
+
screen = { x: 0, y: 0, width: 0, height: 0 };
|
|
104
|
+
url;
|
|
105
|
+
timeoutMs;
|
|
106
|
+
readyTimeoutMs;
|
|
107
|
+
readyPollMs;
|
|
108
|
+
readySettleMs;
|
|
109
|
+
evalBudgetMs;
|
|
110
|
+
evalRetryDelayMs;
|
|
111
|
+
constructor(options) {
|
|
112
|
+
this.url = options.url;
|
|
113
|
+
this.timeoutMs = options.requestTimeoutMs ?? 20_000;
|
|
114
|
+
this.readyTimeoutMs = options.readyTimeoutMs ?? 15_000;
|
|
115
|
+
this.readyPollMs = options.readyPollMs ?? 150;
|
|
116
|
+
this.readySettleMs = options.readySettleMs ?? 500;
|
|
117
|
+
// Derived from the request timeout, never a bare constant: the budget has to
|
|
118
|
+
// leave room for at least one full-length request plus a retry, or it
|
|
119
|
+
// truncates the very first attempt and reports a timeout for a tree walk
|
|
120
|
+
// that was merely slow (a large widget tree can take many seconds).
|
|
121
|
+
this.evalBudgetMs = options.evalBudgetMs ?? this.timeoutMs + 10_000;
|
|
122
|
+
this.evalRetryDelayMs = options.evalRetryDelayMs ?? 250;
|
|
123
|
+
}
|
|
124
|
+
async openSocket() {
|
|
125
|
+
await new Promise((resolve, reject) => {
|
|
126
|
+
const ws = new WebSocket(this.url);
|
|
127
|
+
const onError = () => reject(new AsturError('FLUTTER_VM_CONNECT_FAILED', `Failed to connect to the Flutter Dart VM service at ${this.url}.`));
|
|
128
|
+
ws.addEventListener('open', () => { ws.removeEventListener('error', onError); resolve(); }, { once: true });
|
|
129
|
+
ws.addEventListener('error', onError, { once: true });
|
|
130
|
+
ws.addEventListener('message', (event) => this.onMessage(event));
|
|
131
|
+
ws.addEventListener('close', () => this.failAllPending('Flutter VM service connection closed.'));
|
|
132
|
+
this.ws = ws;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Attaches for network observation only.
|
|
137
|
+
*
|
|
138
|
+
* Deliberately not {@link connect}: that one binds an isolate by evaluating a
|
|
139
|
+
* Dart expression, which needs the expression compiler that `flutter run`
|
|
140
|
+
* attaches. An app launched any other way — `simctl launch` on the iOS
|
|
141
|
+
* simulator, for instance — has a perfectly good VM service with a working
|
|
142
|
+
* HTTP profiler but no compiler, so requiring evaluation rejects a session
|
|
143
|
+
* that can observe traffic fine.
|
|
144
|
+
*
|
|
145
|
+
* Binds on the capability actually needed instead: an isolate that registered
|
|
146
|
+
* the `dart:io` profiler extensions.
|
|
147
|
+
*/
|
|
148
|
+
async connectForNetwork() {
|
|
149
|
+
await this.openSocket();
|
|
150
|
+
return this.resolveIsolate(undefined, 'network');
|
|
151
|
+
}
|
|
152
|
+
async connect() {
|
|
153
|
+
await this.openSocket();
|
|
154
|
+
await this.resolveIsolate();
|
|
155
|
+
// Wait for the first frame so the tree walk doesn't race app startup and so
|
|
156
|
+
// we capture a real screen size (physicalSize is 0x0 until the view lays out).
|
|
157
|
+
await this.waitForReady();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Re-binds to the isolate created by a hot restart. `flutter run`'s `R` tears
|
|
161
|
+
* down the running isolate and starts a *new* one. The old isolate lingers in
|
|
162
|
+
* `getVM` for a moment — and is still readable but FROZEN at its last frame —
|
|
163
|
+
* so binding to it makes tree reads return stale UI (taps reach the live app
|
|
164
|
+
* but the tree never reflects them) or, once it dies, an empty tree. Excluding
|
|
165
|
+
* the pre-restart id is what makes resets land on the live isolate.
|
|
166
|
+
*/
|
|
167
|
+
async reattach() {
|
|
168
|
+
await this.resolveIsolate(this.isolateId);
|
|
169
|
+
return this.waitForReady();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Re-checks readiness on the already-bound isolate without re-resolving it.
|
|
173
|
+
* Used by the reset path to re-wait after re-foregrounding a surfaceless engine
|
|
174
|
+
* (a hot restart can come back with a 0x0 view), so callers can retry cheaply
|
|
175
|
+
* instead of paying the isolate-resolution grace window again.
|
|
176
|
+
*/
|
|
177
|
+
async ensureReady() {
|
|
178
|
+
return this.waitForReady();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Binds {@link isolateId}/{@link rootLibId} to a live, evaluable isolate.
|
|
182
|
+
*
|
|
183
|
+
* When `previousIsolateId` is given (a hot-restart reattach), an isolate with a
|
|
184
|
+
* *different* id is strongly preferred — that's the replacement; the old one is
|
|
185
|
+
* the frozen/dying predecessor. We only fall back to the same id after a short
|
|
186
|
+
* grace window (covers the rare case where a restart reuses the id) so we don't
|
|
187
|
+
* grab the predecessor before its replacement has registered. Each candidate is
|
|
188
|
+
* validated with a trivial eval, since a dying isolate can still be listed yet
|
|
189
|
+
* reject evaluations.
|
|
190
|
+
*/
|
|
191
|
+
async resolveIsolate(previousIsolateId, mode = 'evaluate') {
|
|
192
|
+
const deadline = Date.now() + this.readyTimeoutMs;
|
|
193
|
+
const reuseGraceUntil = Date.now() + 1_500;
|
|
194
|
+
let lastReason = 'no Dart isolate was reported';
|
|
195
|
+
const tryBind = async (candidates) => {
|
|
196
|
+
for (const candidate of candidates) {
|
|
197
|
+
const isolate = await this.call('getIsolate', { isolateId: candidate.id }, deadline).catch(() => undefined);
|
|
198
|
+
const pauseKind = isolate?.pauseEvent?.kind;
|
|
199
|
+
if (pauseKind === 'PauseExit' || pauseKind === 'Exit' || isolate?.runnable === false) {
|
|
200
|
+
lastReason = 'the isolate had already exited';
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (mode === 'network') {
|
|
204
|
+
// Bind on the capability this mode actually needs. An isolate that
|
|
205
|
+
// registered the profiler extensions can serve traffic regardless of
|
|
206
|
+
// whether it can compile expressions.
|
|
207
|
+
const extensions = isolate?.extensionRPCs ?? [];
|
|
208
|
+
if (!extensions.includes('ext.dart.io.getHttpProfile')) {
|
|
209
|
+
lastReason = 'the isolate has not registered the dart:io HTTP profiler extensions';
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
this.isolateId = candidate.id;
|
|
213
|
+
this.rootLibId = isolate?.rootLib?.id;
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
const rootLibId = isolate?.rootLib?.id;
|
|
217
|
+
if (!rootLibId) {
|
|
218
|
+
lastReason = 'the isolate exposed no root library for evaluation';
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
this.isolateId = candidate.id;
|
|
222
|
+
this.rootLibId = rootLibId;
|
|
223
|
+
try {
|
|
224
|
+
await this.evaluateString(READY_EXPR, deadline);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
lastReason = 'the candidate isolate did not accept evaluations yet';
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
};
|
|
233
|
+
for (;;) {
|
|
234
|
+
// Bounded by the same deadline the loop below enforces. Without it a
|
|
235
|
+
// single unresponsive request blocks for the full request timeout and
|
|
236
|
+
// overruns the deadline it is supposed to be respecting.
|
|
237
|
+
const vm = await this.call('getVM', {}, deadline);
|
|
238
|
+
const isolates = vm.isolates ?? [];
|
|
239
|
+
// VM service lists isolates in creation order. Multiple frozen isolates can
|
|
240
|
+
// linger after repeated hot restarts and still accept read-only evaluations,
|
|
241
|
+
// so trying the oldest first can bind a perfectly readable but stale tree.
|
|
242
|
+
// Prefer the most recently created replacement.
|
|
243
|
+
const newestFirst = [...isolates].reverse();
|
|
244
|
+
const fresh = previousIsolateId
|
|
245
|
+
? newestFirst.filter((iso) => iso.id !== previousIsolateId)
|
|
246
|
+
: newestFirst;
|
|
247
|
+
if (await tryBind(fresh)) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
// No replacement isolate yet: only reconsider the previous id after the
|
|
251
|
+
// grace window, in case this restart reused it.
|
|
252
|
+
if (previousIsolateId
|
|
253
|
+
&& fresh.length === 0
|
|
254
|
+
&& Date.now() >= reuseGraceUntil
|
|
255
|
+
&& (await tryBind(newestFirst))) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
if (Date.now() > deadline) {
|
|
259
|
+
throw new AsturError('FLUTTER_VM_NO_ISOLATE', `Could not bind to the Flutter Dart isolate (${lastReason}).`);
|
|
260
|
+
}
|
|
261
|
+
await this.sleep(this.readyPollMs);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async getTree() {
|
|
265
|
+
if (this.screen.width === 0 || this.screen.height === 0) {
|
|
266
|
+
// connect() timed out before the first frame, or the view was resized to
|
|
267
|
+
// zero; re-establish a stable frame before reading.
|
|
268
|
+
await this.waitForReady();
|
|
269
|
+
}
|
|
270
|
+
const children = await this.extractChildren();
|
|
271
|
+
return {
|
|
272
|
+
type: 'FlutterView',
|
|
273
|
+
enabled: true,
|
|
274
|
+
visible: true,
|
|
275
|
+
bounds: this.screen,
|
|
276
|
+
children,
|
|
277
|
+
platform: 'android'
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Runs the on-device tree walk and rebuilds the flat, parent-annotated output
|
|
282
|
+
* into a nested snapshot tree. Nesting matters because page logic reads a
|
|
283
|
+
* container's subtree (e.g. the counters under a tap-lab card) — a flat list
|
|
284
|
+
* would leave every container childless. Rows are emitted in pre-order, so a
|
|
285
|
+
* parent always precedes its children and the map is fully populated by the
|
|
286
|
+
* time we wire up links.
|
|
287
|
+
*/
|
|
288
|
+
async extractChildren() {
|
|
289
|
+
const raw = await this.evaluateStringStable(EXTRACT_EXPR);
|
|
290
|
+
const rows = raw
|
|
291
|
+
.split('\n')
|
|
292
|
+
.filter((line) => line.length > 0)
|
|
293
|
+
.map((line) => this.parseRow(line))
|
|
294
|
+
.filter((row) => row !== undefined);
|
|
295
|
+
const byId = new Map();
|
|
296
|
+
for (const row of rows) {
|
|
297
|
+
byId.set(row.nodeId, row.node);
|
|
298
|
+
}
|
|
299
|
+
const roots = [];
|
|
300
|
+
for (const row of rows) {
|
|
301
|
+
const parent = byId.get(row.parentId);
|
|
302
|
+
if (parent) {
|
|
303
|
+
parent.children.push(row.node);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// parentId 0 (the synthetic root) or a pruned ancestor → top level.
|
|
307
|
+
roots.push(row.node);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return roots;
|
|
311
|
+
}
|
|
312
|
+
/** Dismisses the soft keyboard by clearing the Flutter primary focus. */
|
|
313
|
+
async unfocus() {
|
|
314
|
+
await this.evaluateStringStable(UNFOCUS_EXPR);
|
|
315
|
+
}
|
|
316
|
+
async dispose() {
|
|
317
|
+
this.failAllPending('Flutter VM service disposed.');
|
|
318
|
+
try {
|
|
319
|
+
this.ws?.close();
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// ignore
|
|
323
|
+
}
|
|
324
|
+
this.ws = undefined;
|
|
325
|
+
}
|
|
326
|
+
parseRow(line) {
|
|
327
|
+
const cols = line.split(SEP);
|
|
328
|
+
if (cols.length < 11) {
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
const [nodeId, parentId, id, text, label, type, x, y, w, h, vis, fieldValue] = cols;
|
|
332
|
+
const bounds = {
|
|
333
|
+
x: Number.parseInt(x, 10) || 0,
|
|
334
|
+
y: Number.parseInt(y, 10) || 0,
|
|
335
|
+
width: Number.parseInt(w, 10) || 0,
|
|
336
|
+
height: Number.parseInt(h, 10) || 0
|
|
337
|
+
};
|
|
338
|
+
return {
|
|
339
|
+
nodeId: Number.parseInt(nodeId, 10) || 0,
|
|
340
|
+
parentId: Number.parseInt(parentId, 10) || 0,
|
|
341
|
+
node: {
|
|
342
|
+
id: id || undefined,
|
|
343
|
+
text: text || undefined,
|
|
344
|
+
label: label || undefined,
|
|
345
|
+
// Text-field value (typed text, or placeholder when empty); falls back to a
|
|
346
|
+
// Text widget's data so plain labels still expose a value.
|
|
347
|
+
value: fieldValue || text || undefined,
|
|
348
|
+
type: type || 'FlutterWidget',
|
|
349
|
+
enabled: true,
|
|
350
|
+
visible: vis === '1',
|
|
351
|
+
bounds,
|
|
352
|
+
children: [],
|
|
353
|
+
platform: 'android'
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Blocks until the app's UI has settled, so the first read returns fully
|
|
359
|
+
* laid-out bounds rather than zeros.
|
|
360
|
+
*
|
|
361
|
+
* Two phases:
|
|
362
|
+
* 1. Wait for a completed frame (scheduler idle) with a non-zero screen size —
|
|
363
|
+
* captures the real physical size, which is 0x0 until the view lays out.
|
|
364
|
+
* 2. Wait for the laid-out element set to stop changing across consecutive
|
|
365
|
+
* polls. This is necessary because parts of the tree (e.g. a bottom
|
|
366
|
+
* navigation bar) can lay out a frame or two after the first frame, so they
|
|
367
|
+
* report zero bounds immediately after step 1 — tapping such a node would
|
|
368
|
+
* hit the wrong coordinates. The fingerprint keys on which nodes are present
|
|
369
|
+
* and laid out, not their exact bounds, so a continuously-animating app
|
|
370
|
+
* still settles instead of polling until the timeout.
|
|
371
|
+
*/
|
|
372
|
+
async waitForReady() {
|
|
373
|
+
const deadline = Date.now() + this.readyTimeoutMs;
|
|
374
|
+
// Phase 1 — a known screen size (physicalSize is 0x0 until the view lays out).
|
|
375
|
+
// Idle is not required here: a continuously-animating app never reports idle,
|
|
376
|
+
// and phase 2 provides the real layout guarantee.
|
|
377
|
+
for (;;) {
|
|
378
|
+
let raw = '0:0:0';
|
|
379
|
+
try {
|
|
380
|
+
raw = await this.evaluateString(READY_EXPR);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// Transient during isolate warm-up; retry until the deadline.
|
|
384
|
+
}
|
|
385
|
+
const [, wRaw, hRaw] = raw.split(':');
|
|
386
|
+
const w = Number.parseInt(wRaw, 10);
|
|
387
|
+
const h = Number.parseInt(hRaw, 10);
|
|
388
|
+
if (Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0) {
|
|
389
|
+
this.screen = { x: 0, y: 0, width: w, height: h };
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
if (Date.now() >= deadline) {
|
|
393
|
+
// Never captured a real screen size: the engine is surfaceless (a 0x0
|
|
394
|
+
// view after a hot restart). Report it so the reset path can re-foreground
|
|
395
|
+
// and retry instead of serving an unlaid-out tree.
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
await this.sleep(this.readyPollMs);
|
|
399
|
+
}
|
|
400
|
+
// Phase 2 — wait for the laid-out element set to stabilize.
|
|
401
|
+
let previous;
|
|
402
|
+
let settleStart = 0;
|
|
403
|
+
for (;;) {
|
|
404
|
+
let fingerprint = '';
|
|
405
|
+
try {
|
|
406
|
+
fingerprint = this.layoutFingerprint(await this.extractChildren());
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// Mid-build; retry until the deadline.
|
|
410
|
+
}
|
|
411
|
+
if (fingerprint && fingerprint === previous) {
|
|
412
|
+
if (settleStart === 0) {
|
|
413
|
+
settleStart = Date.now();
|
|
414
|
+
}
|
|
415
|
+
if (Date.now() - settleStart >= this.readySettleMs) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
settleStart = 0;
|
|
421
|
+
previous = fingerprint;
|
|
422
|
+
}
|
|
423
|
+
if (Date.now() >= deadline) {
|
|
424
|
+
// The view reported a real size (Phase 1 passed); the laid-out set just
|
|
425
|
+
// never fully settled. That is still usable, so treat it as ready.
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
await this.sleep(this.readyPollMs);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/** Identity of the laid-out, labelled nodes — present-and-sized, ignoring exact position so animations still settle. Walks the (now nested) tree. */
|
|
432
|
+
layoutFingerprint(roots) {
|
|
433
|
+
const parts = [];
|
|
434
|
+
const walk = (node) => {
|
|
435
|
+
if (node.bounds.width > 0 && node.bounds.height > 0) {
|
|
436
|
+
parts.push(`${node.id ?? ''}#${node.text ?? ''}#${node.label ?? ''}`);
|
|
437
|
+
}
|
|
438
|
+
for (const child of node.children) {
|
|
439
|
+
walk(child);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
for (const root of roots) {
|
|
443
|
+
walk(root);
|
|
444
|
+
}
|
|
445
|
+
return parts.sort().join('|');
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Evaluates the on-device tree walk, retrying transient build-lock failures.
|
|
449
|
+
*
|
|
450
|
+
* The walk uses `visitChildren`, which throws if it runs while Flutter is mid-build
|
|
451
|
+
* (app startup, route transitions, animations). Those settle within a frame or two,
|
|
452
|
+
* so a short bounded retry makes reads reliable without callers having to sleep.
|
|
453
|
+
*/
|
|
454
|
+
async evaluateStringStable(expression) {
|
|
455
|
+
// Bound the whole retry sequence by wall clock, and hand the same deadline
|
|
456
|
+
// down to each RPC so a single hung request cannot consume the budget on
|
|
457
|
+
// its own. Callers poll this through `waitFor`, which only re-checks its
|
|
458
|
+
// own deadline *between* attempts — an unbounded evaluate here therefore
|
|
459
|
+
// reads as a frozen test rather than a timeout, no matter how short the
|
|
460
|
+
// caller's timeout is.
|
|
461
|
+
const deadline = Date.now() + this.evalBudgetMs;
|
|
462
|
+
let lastError;
|
|
463
|
+
let attempts = 0;
|
|
464
|
+
for (;;) {
|
|
465
|
+
attempts += 1;
|
|
466
|
+
try {
|
|
467
|
+
return await this.evaluateString(expression, deadline);
|
|
468
|
+
}
|
|
469
|
+
catch (err) {
|
|
470
|
+
const transientCompilationError = err instanceof AsturError
|
|
471
|
+
&& err.code === 'FLUTTER_VM_RPC_ERROR'
|
|
472
|
+
&& /expression compilation error/i.test(err.message);
|
|
473
|
+
if (!(err instanceof AsturError)
|
|
474
|
+
|| (err.code !== 'FLUTTER_VM_EVAL_FAILED' && !transientCompilationError)) {
|
|
475
|
+
throw err;
|
|
476
|
+
}
|
|
477
|
+
lastError = err;
|
|
478
|
+
if (Date.now() + this.evalRetryDelayMs >= deadline) {
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
await this.sleep(this.evalRetryDelayMs);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const expressionName = expression === EXTRACT_EXPR
|
|
485
|
+
? 'Flutter tree extraction'
|
|
486
|
+
: expression === UNFOCUS_EXPR
|
|
487
|
+
? 'Flutter keyboard unfocus'
|
|
488
|
+
: 'Flutter expression';
|
|
489
|
+
throw new AsturError('FLUTTER_VM_EVAL_FAILED', `${expressionName} failed after ${attempts} attempt(s) within ${this.evalBudgetMs} ms: ${lastError instanceof Error ? lastError.message : 'unknown evaluation error'}`, { cause: lastError });
|
|
490
|
+
}
|
|
491
|
+
sleep(ms) {
|
|
492
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Evaluates a Dart expression and returns its full String result (handles VM
|
|
496
|
+
* string truncation). `deadline` caps every RPC this makes, so paging a large
|
|
497
|
+
* tree cannot outlive the caller's retry budget.
|
|
498
|
+
*/
|
|
499
|
+
async evaluateString(expression, deadline) {
|
|
500
|
+
const result = await this.call('evaluate', {
|
|
501
|
+
isolateId: this.isolateId,
|
|
502
|
+
targetId: this.rootLibId,
|
|
503
|
+
expression
|
|
504
|
+
}, deadline);
|
|
505
|
+
if (result.kind === 'Error' || result.type === '@Error') {
|
|
506
|
+
throw new AsturError('FLUTTER_VM_EVAL_FAILED', 'Flutter VM expression evaluation failed.', { result });
|
|
507
|
+
}
|
|
508
|
+
if (result.kind !== 'String') {
|
|
509
|
+
return '';
|
|
510
|
+
}
|
|
511
|
+
if (!result.valueAsStringIsTruncated) {
|
|
512
|
+
return result.valueAsString ?? '';
|
|
513
|
+
}
|
|
514
|
+
// Large result: page the full string in via getObject.
|
|
515
|
+
const objectId = result.id;
|
|
516
|
+
let out = '';
|
|
517
|
+
let offset = 0;
|
|
518
|
+
const count = 100_000;
|
|
519
|
+
// The total length is reported on the (truncated) instance.
|
|
520
|
+
const total = typeof result.length === 'number' ? result.length : Number.MAX_SAFE_INTEGER;
|
|
521
|
+
while (out.length < total) {
|
|
522
|
+
const obj = await this.call('getObject', { isolateId: this.isolateId, objectId, offset, count }, deadline);
|
|
523
|
+
const chunk = obj.valueAsString ?? '';
|
|
524
|
+
if (chunk.length === 0) {
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
out += chunk;
|
|
528
|
+
offset += chunk.length;
|
|
529
|
+
}
|
|
530
|
+
return out;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Turns on the Dart VM's HTTP profiler for this isolate.
|
|
534
|
+
*
|
|
535
|
+
* Off by default: with it on the VM retains every request (and its body) for
|
|
536
|
+
* the life of the isolate, so it is enabled only when a test asks to observe,
|
|
537
|
+
* and the buffer is cleared between tests.
|
|
538
|
+
*/
|
|
539
|
+
async enableHttpProfiling() {
|
|
540
|
+
await this.call('ext.dart.io.httpEnableTimelineLogging', {
|
|
541
|
+
isolateId: this.isolateId,
|
|
542
|
+
enabled: true
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
/** Drops everything the profiler has buffered so far. */
|
|
546
|
+
async clearHttpProfile() {
|
|
547
|
+
await this.call('ext.dart.io.clearHttpProfile', { isolateId: this.isolateId });
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Returns the profiler's buffered requests, newest state included.
|
|
551
|
+
*
|
|
552
|
+
* The response shape is owned by the Dart SDK and has changed between
|
|
553
|
+
* versions, so callers must treat every field as optional rather than
|
|
554
|
+
* trusting a schema — see `toNetworkRecords` in the Android driver.
|
|
555
|
+
*/
|
|
556
|
+
async getHttpProfile() {
|
|
557
|
+
return this.call('ext.dart.io.getHttpProfile', { isolateId: this.isolateId });
|
|
558
|
+
}
|
|
559
|
+
/** Full detail (including the response body) for one profiled request. */
|
|
560
|
+
async getHttpProfileRequest(id) {
|
|
561
|
+
return this.call('ext.dart.io.getHttpProfileRequest', { isolateId: this.isolateId, id });
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Whether this isolate actually registered the dart:io HTTP profiler
|
|
565
|
+
* extensions. They are absent in some builds, so capability is detected at
|
|
566
|
+
* runtime rather than assumed from the platform.
|
|
567
|
+
*/
|
|
568
|
+
async supportsHttpProfiling() {
|
|
569
|
+
const isolate = await this.call('getIsolate', { isolateId: this.isolateId }).catch(() => undefined);
|
|
570
|
+
const extensions = isolate?.extensionRPCs ?? [];
|
|
571
|
+
return extensions.includes('ext.dart.io.getHttpProfile');
|
|
572
|
+
}
|
|
573
|
+
call(method, params = {}, deadline) {
|
|
574
|
+
const ws = this.ws;
|
|
575
|
+
if (!ws) {
|
|
576
|
+
return Promise.reject(new AsturError('FLUTTER_VM_NOT_CONNECTED', 'Flutter VM service is not connected.'));
|
|
577
|
+
}
|
|
578
|
+
// Never exceed the caller's remaining budget, but always allow a small floor
|
|
579
|
+
// so an almost-expired deadline still issues a real request rather than a
|
|
580
|
+
// guaranteed-zero-timeout one.
|
|
581
|
+
const timeoutMs = deadline === undefined
|
|
582
|
+
? this.timeoutMs
|
|
583
|
+
: Math.max(250, Math.min(this.timeoutMs, deadline - Date.now()));
|
|
584
|
+
const id = this.nextId++;
|
|
585
|
+
return new Promise((resolve, reject) => {
|
|
586
|
+
const timer = setTimeout(() => {
|
|
587
|
+
this.pending.delete(id);
|
|
588
|
+
reject(new AsturError('FLUTTER_VM_TIMEOUT', `Flutter VM service request '${method}' timed out after ${timeoutMs} ms.`));
|
|
589
|
+
}, timeoutMs);
|
|
590
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
591
|
+
ws.send(JSON.stringify({ jsonrpc: '2.0', id, method, params }));
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
onMessage(event) {
|
|
595
|
+
let message;
|
|
596
|
+
try {
|
|
597
|
+
message = JSON.parse(typeof event.data === 'string' ? event.data : String(event.data));
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
if (typeof message.id !== 'number') {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const entry = this.pending.get(message.id);
|
|
606
|
+
if (!entry) {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
this.pending.delete(message.id);
|
|
610
|
+
clearTimeout(entry.timer);
|
|
611
|
+
if (message.error) {
|
|
612
|
+
const detail = message.error.data === undefined
|
|
613
|
+
? ''
|
|
614
|
+
: `: ${typeof message.error.data === 'string'
|
|
615
|
+
? message.error.data
|
|
616
|
+
: JSON.stringify(message.error.data)}`;
|
|
617
|
+
entry.reject(new AsturError('FLUTTER_VM_RPC_ERROR', `${message.error.message ?? 'Flutter VM service returned an error'}${detail}`, { data: message.error.data }));
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
entry.resolve(message.result ?? {});
|
|
621
|
+
}
|
|
622
|
+
failAllPending(reason) {
|
|
623
|
+
for (const [, entry] of this.pending) {
|
|
624
|
+
clearTimeout(entry.timer);
|
|
625
|
+
entry.reject(new AsturError('FLUTTER_VM_DISCONNECTED', reason));
|
|
626
|
+
}
|
|
627
|
+
this.pending.clear();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
//# sourceMappingURL=vmService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vmService.js","sourceRoot":"","sources":["../../src/flutter/vmService.ts"],"names":[],"mappings":"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"}
|