@midscene/android 0.13.1 → 0.13.2-beta-20250401015137.0
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/README.md +14 -0
- package/bin/yadb +0 -0
- package/dist/es/index.d.ts +81 -1
- package/dist/es/index.js +326 -3
- package/dist/lib/index.d.ts +81 -1
- package/dist/lib/index.js +336 -3
- package/dist/types/index.d.ts +81 -1
- package/package.json +17 -8
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Android prerequisites
|
|
2
|
+
|
|
3
|
+
Android is driven by adb, so you need install adb first:
|
|
4
|
+
- [CLI](https://developer.android.com/tools/adb)
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm run test:ai -- setting.test.ts
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
or
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm run test:ai -- todo.test.ts
|
|
14
|
+
```
|
package/bin/yadb
ADDED
|
Binary file
|
package/dist/es/index.d.ts
CHANGED
|
@@ -1 +1,81 @@
|
|
|
1
|
-
|
|
1
|
+
import { AbstractPage } from '@midscene/web';
|
|
2
|
+
export { PageAgent as AndroidAgent } from '@midscene/web';
|
|
3
|
+
import { Size, Point } from '@midscene/core';
|
|
4
|
+
import { ElementInfo } from '@midscene/shared/extractor';
|
|
5
|
+
import { ADB } from 'appium-adb';
|
|
6
|
+
|
|
7
|
+
declare class Page implements AbstractPage {
|
|
8
|
+
private deviceId;
|
|
9
|
+
private screenSize;
|
|
10
|
+
private yadbPushed;
|
|
11
|
+
private deviceRatio;
|
|
12
|
+
private adbInitPromise;
|
|
13
|
+
pageType: string;
|
|
14
|
+
constructor({ deviceId }: {
|
|
15
|
+
deviceId: string;
|
|
16
|
+
});
|
|
17
|
+
private initAdb;
|
|
18
|
+
getAdb(): Promise<ADB>;
|
|
19
|
+
private execYadb;
|
|
20
|
+
getElementsInfo(): Promise<ElementInfo[]>;
|
|
21
|
+
getElementsNodeTree(): Promise<any>;
|
|
22
|
+
size(): Promise<Size>;
|
|
23
|
+
/**
|
|
24
|
+
* Convert logical coordinates to physical coordinates, handling device ratio
|
|
25
|
+
* @param x Logical X coordinate
|
|
26
|
+
* @param y Logical Y coordinate
|
|
27
|
+
* @returns Physical coordinate point
|
|
28
|
+
*/
|
|
29
|
+
private adjustCoordinates;
|
|
30
|
+
/**
|
|
31
|
+
* Convert physical coordinates to logical coordinates, handling device ratio
|
|
32
|
+
* @param x Physical X coordinate
|
|
33
|
+
* @param y Physical Y coordinate
|
|
34
|
+
* @returns Logical coordinate point
|
|
35
|
+
*/
|
|
36
|
+
private reverseAdjustCoordinates;
|
|
37
|
+
screenshotBase64(): Promise<string>;
|
|
38
|
+
get mouse(): {
|
|
39
|
+
click: (x: number, y: number) => Promise<void>;
|
|
40
|
+
wheel: (deltaX: number, deltaY: number) => Promise<void>;
|
|
41
|
+
move: (x: number, y: number) => Promise<void>;
|
|
42
|
+
drag: (from: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
}, to: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
}) => Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
get keyboard(): {
|
|
51
|
+
type: (text: string) => Promise<void>;
|
|
52
|
+
press: (action: {
|
|
53
|
+
key: string;
|
|
54
|
+
command?: string;
|
|
55
|
+
} | {
|
|
56
|
+
key: string;
|
|
57
|
+
command?: string;
|
|
58
|
+
}[]) => Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
clearInput(element: ElementInfo): Promise<void>;
|
|
61
|
+
url(): Promise<string>;
|
|
62
|
+
scrollUntilTop(startingPoint?: Point): Promise<void>;
|
|
63
|
+
scrollUntilBottom(startingPoint?: Point): Promise<void>;
|
|
64
|
+
scrollUntilLeft(startingPoint?: Point): Promise<void>;
|
|
65
|
+
scrollUntilRight(startingPoint?: Point): Promise<void>;
|
|
66
|
+
scrollUp(distance?: number, startingPoint?: Point): Promise<void>;
|
|
67
|
+
scrollDown(distance?: number, startingPoint?: Point): Promise<void>;
|
|
68
|
+
scrollLeft(distance?: number, startingPoint?: Point): Promise<void>;
|
|
69
|
+
scrollRight(distance?: number, startingPoint?: Point): Promise<void>;
|
|
70
|
+
private pushYadb;
|
|
71
|
+
private keyboardType;
|
|
72
|
+
private keyboardPress;
|
|
73
|
+
private keyboardPressAction;
|
|
74
|
+
private mouseClick;
|
|
75
|
+
private mouseMove;
|
|
76
|
+
private mouseDrag;
|
|
77
|
+
private mouseWheel;
|
|
78
|
+
destroy(): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { Page as AndroidPage };
|
package/dist/es/index.js
CHANGED
|
@@ -1,6 +1,329 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import { PageAgent } from "@midscene/web";
|
|
3
|
+
|
|
4
|
+
// src/page/index.ts
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { getTmpFile } from "@midscene/core/utils";
|
|
8
|
+
import { resizeImg } from "@midscene/shared/img";
|
|
9
|
+
import { getDebug } from "@midscene/shared/logger";
|
|
10
|
+
import { ADB } from "appium-adb";
|
|
11
|
+
var debugPage = getDebug("android");
|
|
12
|
+
var Page = class {
|
|
13
|
+
constructor({ deviceId }) {
|
|
14
|
+
this.screenSize = null;
|
|
15
|
+
this.yadbPushed = false;
|
|
16
|
+
this.deviceRatio = 1;
|
|
17
|
+
this.pageType = "android";
|
|
18
|
+
this.deviceId = deviceId;
|
|
19
|
+
this.adbInitPromise = this.initAdb();
|
|
20
|
+
}
|
|
21
|
+
async initAdb() {
|
|
22
|
+
debugPage(`Initializing ADB with device ID: ${this.deviceId}`);
|
|
23
|
+
const adb = await ADB.createADB({
|
|
24
|
+
udid: this.deviceId,
|
|
25
|
+
adbExecTimeout: 6e4
|
|
26
|
+
});
|
|
27
|
+
debugPage("ADB initialized successfully");
|
|
28
|
+
return adb;
|
|
29
|
+
}
|
|
30
|
+
async getAdb() {
|
|
31
|
+
return this.adbInitPromise;
|
|
32
|
+
}
|
|
33
|
+
async execYadb(keyboardContent) {
|
|
34
|
+
await this.pushYadb();
|
|
35
|
+
const adb = await this.getAdb();
|
|
36
|
+
await adb.shell(
|
|
37
|
+
`app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
async getElementsInfo() {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
async getElementsNodeTree() {
|
|
44
|
+
return {
|
|
45
|
+
node: null,
|
|
46
|
+
children: []
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async size() {
|
|
50
|
+
if (this.screenSize) {
|
|
51
|
+
return this.screenSize;
|
|
52
|
+
}
|
|
53
|
+
const adb = await this.getAdb();
|
|
54
|
+
const screenSize = await adb.getScreenSize();
|
|
55
|
+
let width;
|
|
56
|
+
let height;
|
|
57
|
+
if (typeof screenSize === "string") {
|
|
58
|
+
const match = screenSize.match(/(\d+)x(\d+)/);
|
|
59
|
+
if (!match || match.length < 3) {
|
|
60
|
+
throw new Error(`Unable to parse screen size: ${screenSize}`);
|
|
61
|
+
}
|
|
62
|
+
width = Number.parseInt(match[1], 10);
|
|
63
|
+
height = Number.parseInt(match[2], 10);
|
|
64
|
+
} else if (typeof screenSize === "object" && screenSize !== null) {
|
|
65
|
+
const sizeObj = screenSize;
|
|
66
|
+
if ("width" in sizeObj && "height" in sizeObj) {
|
|
67
|
+
width = Number(sizeObj.width);
|
|
68
|
+
height = Number(sizeObj.height);
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid screen size object: ${JSON.stringify(screenSize)}`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
throw new Error(`Invalid screen size format: ${screenSize}`);
|
|
76
|
+
}
|
|
77
|
+
const densityNum = await adb.getScreenDensity();
|
|
78
|
+
this.deviceRatio = Number(densityNum) / 160;
|
|
79
|
+
const { x: logicalWidth, y: logicalHeight } = this.reverseAdjustCoordinates(
|
|
80
|
+
width,
|
|
81
|
+
height
|
|
82
|
+
);
|
|
83
|
+
this.screenSize = {
|
|
84
|
+
width: logicalWidth,
|
|
85
|
+
height: logicalHeight
|
|
86
|
+
};
|
|
87
|
+
return this.screenSize;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Convert logical coordinates to physical coordinates, handling device ratio
|
|
91
|
+
* @param x Logical X coordinate
|
|
92
|
+
* @param y Logical Y coordinate
|
|
93
|
+
* @returns Physical coordinate point
|
|
94
|
+
*/
|
|
95
|
+
adjustCoordinates(x, y) {
|
|
96
|
+
const ratio = this.deviceRatio;
|
|
97
|
+
return {
|
|
98
|
+
x: Math.round(x * ratio),
|
|
99
|
+
y: Math.round(y * ratio)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Convert physical coordinates to logical coordinates, handling device ratio
|
|
104
|
+
* @param x Physical X coordinate
|
|
105
|
+
* @param y Physical Y coordinate
|
|
106
|
+
* @returns Logical coordinate point
|
|
107
|
+
*/
|
|
108
|
+
reverseAdjustCoordinates(x, y) {
|
|
109
|
+
const ratio = this.deviceRatio;
|
|
110
|
+
return {
|
|
111
|
+
x: Math.round(x / ratio),
|
|
112
|
+
y: Math.round(y / ratio)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async screenshotBase64() {
|
|
116
|
+
debugPage("screenshotBase64 begin");
|
|
117
|
+
const { width, height } = await this.size();
|
|
118
|
+
const adb = await this.getAdb();
|
|
119
|
+
let screenshotBuffer;
|
|
120
|
+
try {
|
|
121
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const screenshotPath = getTmpFile("png");
|
|
124
|
+
await adb.shell("screencap -p /sdcard/screenshot.png");
|
|
125
|
+
await adb.pull("/sdcard/screenshot.png", screenshotPath);
|
|
126
|
+
screenshotBuffer = await fs.promises.readFile(screenshotPath);
|
|
127
|
+
}
|
|
128
|
+
const resizedScreenshotBuffer = await resizeImg(screenshotBuffer, {
|
|
129
|
+
width,
|
|
130
|
+
height
|
|
131
|
+
});
|
|
132
|
+
const result = `data:image/jpeg;base64,${resizedScreenshotBuffer.toString("base64")}`;
|
|
133
|
+
debugPage("screenshotBase64 end");
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
get mouse() {
|
|
137
|
+
return {
|
|
138
|
+
click: (x, y) => this.mouseClick(x, y),
|
|
139
|
+
wheel: (deltaX, deltaY) => this.mouseWheel(deltaX, deltaY),
|
|
140
|
+
move: (x, y) => this.mouseMove(x, y),
|
|
141
|
+
drag: (from, to) => this.mouseDrag(from, to)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
get keyboard() {
|
|
145
|
+
return {
|
|
146
|
+
type: (text) => this.keyboardType(text),
|
|
147
|
+
press: (action) => this.keyboardPressAction(action)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async clearInput(element) {
|
|
151
|
+
if (!element) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
await this.pushYadb();
|
|
155
|
+
const adb = await this.getAdb();
|
|
156
|
+
await adb.shell(
|
|
157
|
+
'app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "~CLEAR~"'
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
async url() {
|
|
161
|
+
const adb = await this.getAdb();
|
|
162
|
+
const { appPackage, appActivity } = await adb.getFocusedPackageAndActivity();
|
|
163
|
+
return `${appPackage}/${appActivity}`;
|
|
164
|
+
}
|
|
165
|
+
async scrollUntilTop(startingPoint) {
|
|
166
|
+
if (startingPoint) {
|
|
167
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
168
|
+
}
|
|
169
|
+
await this.mouseWheel(0, 9999999, 100);
|
|
170
|
+
}
|
|
171
|
+
async scrollUntilBottom(startingPoint) {
|
|
172
|
+
if (startingPoint) {
|
|
173
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
174
|
+
}
|
|
175
|
+
await this.mouseWheel(0, -9999999, 100);
|
|
176
|
+
}
|
|
177
|
+
async scrollUntilLeft(startingPoint) {
|
|
178
|
+
if (startingPoint) {
|
|
179
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
180
|
+
}
|
|
181
|
+
await this.mouseWheel(9999999, 0, 100);
|
|
182
|
+
}
|
|
183
|
+
async scrollUntilRight(startingPoint) {
|
|
184
|
+
if (startingPoint) {
|
|
185
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
186
|
+
}
|
|
187
|
+
await this.mouseWheel(-9999999, 0, 100);
|
|
188
|
+
}
|
|
189
|
+
async scrollUp(distance, startingPoint) {
|
|
190
|
+
const { height } = await this.size();
|
|
191
|
+
const scrollDistance = distance || height * 0.7;
|
|
192
|
+
if (startingPoint) {
|
|
193
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
194
|
+
}
|
|
195
|
+
await this.mouseWheel(0, scrollDistance, 1e3);
|
|
196
|
+
}
|
|
197
|
+
async scrollDown(distance, startingPoint) {
|
|
198
|
+
const { height } = await this.size();
|
|
199
|
+
const scrollDistance = distance || height * 0.7;
|
|
200
|
+
if (startingPoint) {
|
|
201
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
202
|
+
}
|
|
203
|
+
await this.mouseWheel(0, -scrollDistance, 1e3);
|
|
204
|
+
}
|
|
205
|
+
async scrollLeft(distance, startingPoint) {
|
|
206
|
+
const { width } = await this.size();
|
|
207
|
+
const scrollDistance = distance || width * 0.7;
|
|
208
|
+
if (startingPoint) {
|
|
209
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
210
|
+
}
|
|
211
|
+
await this.mouseWheel(scrollDistance, 0, 1e3);
|
|
212
|
+
}
|
|
213
|
+
async scrollRight(distance, startingPoint) {
|
|
214
|
+
const { width } = await this.size();
|
|
215
|
+
const scrollDistance = distance || width * 0.7;
|
|
216
|
+
if (startingPoint) {
|
|
217
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
218
|
+
}
|
|
219
|
+
await this.mouseWheel(-scrollDistance, 0, 1e3);
|
|
220
|
+
}
|
|
221
|
+
async pushYadb() {
|
|
222
|
+
if (!this.yadbPushed) {
|
|
223
|
+
const adb = await this.getAdb();
|
|
224
|
+
const yadbBin = path.join(__dirname, "../../bin/yadb");
|
|
225
|
+
await adb.push(yadbBin, "/data/local/tmp");
|
|
226
|
+
this.yadbPushed = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async keyboardType(text) {
|
|
230
|
+
if (!text)
|
|
231
|
+
return;
|
|
232
|
+
const adb = await this.getAdb();
|
|
233
|
+
const isChinese = /[\p{Script=Han}\p{sc=Hani}]/u.test(text);
|
|
234
|
+
if (!isChinese) {
|
|
235
|
+
await adb.inputText(text);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
await this.execYadb(text);
|
|
239
|
+
}
|
|
240
|
+
async keyboardPress(key) {
|
|
241
|
+
const keyCodeMap = {
|
|
242
|
+
Enter: 66,
|
|
243
|
+
Backspace: 67,
|
|
244
|
+
Tab: 61,
|
|
245
|
+
ArrowUp: 19,
|
|
246
|
+
ArrowDown: 20,
|
|
247
|
+
ArrowLeft: 21,
|
|
248
|
+
ArrowRight: 22,
|
|
249
|
+
Escape: 111,
|
|
250
|
+
Home: 3,
|
|
251
|
+
End: 123
|
|
252
|
+
};
|
|
253
|
+
const adb = await this.getAdb();
|
|
254
|
+
const keyCode = keyCodeMap[key];
|
|
255
|
+
if (keyCode !== void 0) {
|
|
256
|
+
await adb.keyevent(keyCode);
|
|
257
|
+
} else {
|
|
258
|
+
if (key.length === 1) {
|
|
259
|
+
const asciiCode = key.toUpperCase().charCodeAt(0);
|
|
260
|
+
if (asciiCode >= 65 && asciiCode <= 90) {
|
|
261
|
+
await adb.keyevent(asciiCode - 36);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async keyboardPressAction(action) {
|
|
267
|
+
if (Array.isArray(action)) {
|
|
268
|
+
for (const act of action) {
|
|
269
|
+
await this.keyboardPress(act.key);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
await this.keyboardPress(action.key);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async mouseClick(x, y) {
|
|
276
|
+
await this.mouseMove(x, y);
|
|
277
|
+
const adb = await this.getAdb();
|
|
278
|
+
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
279
|
+
await adb.shell(`input tap ${adjustedX} ${adjustedY}`);
|
|
280
|
+
}
|
|
281
|
+
async mouseMove(x, y) {
|
|
282
|
+
return Promise.resolve();
|
|
283
|
+
}
|
|
284
|
+
async mouseDrag(from, to) {
|
|
285
|
+
const adb = await this.getAdb();
|
|
286
|
+
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
287
|
+
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
288
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} 300`);
|
|
289
|
+
}
|
|
290
|
+
async mouseWheel(deltaX, deltaY, duration = 1e3) {
|
|
291
|
+
const { width, height } = await this.size();
|
|
292
|
+
const n = 4;
|
|
293
|
+
const startX = deltaX < 0 ? (n - 1) * (width / n) : width / n;
|
|
294
|
+
const startY = deltaY < 0 ? (n - 1) * (height / n) : height / n;
|
|
295
|
+
const maxNegativeDeltaX = startX;
|
|
296
|
+
const maxPositiveDeltaX = (n - 1) * (width / n);
|
|
297
|
+
const maxNegativeDeltaY = startY;
|
|
298
|
+
const maxPositiveDeltaY = (n - 1) * (height / n);
|
|
299
|
+
deltaX = Math.max(-maxNegativeDeltaX, Math.min(deltaX, maxPositiveDeltaX));
|
|
300
|
+
deltaY = Math.max(-maxNegativeDeltaY, Math.min(deltaY, maxPositiveDeltaY));
|
|
301
|
+
const endX = startX + deltaX;
|
|
302
|
+
const endY = startY + deltaY;
|
|
303
|
+
const { x: adjustedStartX, y: adjustedStartY } = this.adjustCoordinates(
|
|
304
|
+
startX,
|
|
305
|
+
startY
|
|
306
|
+
);
|
|
307
|
+
const { x: adjustedEndX, y: adjustedEndY } = this.adjustCoordinates(
|
|
308
|
+
endX,
|
|
309
|
+
endY
|
|
310
|
+
);
|
|
311
|
+
const adb = await this.getAdb();
|
|
312
|
+
await adb.shell(
|
|
313
|
+
`input swipe ${adjustedStartX} ${adjustedStartY} ${adjustedEndX} ${adjustedEndY} ${duration}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
async destroy() {
|
|
317
|
+
try {
|
|
318
|
+
const adb = await this.getAdb();
|
|
319
|
+
await adb.shell("rm -f /sdcard/screenshot.png");
|
|
320
|
+
await adb.shell("rm -f /sdcard/window_dump.xml");
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error("Error during cleanup:", error);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
3
326
|
export {
|
|
4
|
-
AndroidAgent,
|
|
5
|
-
AndroidPage
|
|
327
|
+
PageAgent as AndroidAgent,
|
|
328
|
+
Page as AndroidPage
|
|
6
329
|
};
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1 +1,81 @@
|
|
|
1
|
-
|
|
1
|
+
import { AbstractPage } from '@midscene/web';
|
|
2
|
+
export { PageAgent as AndroidAgent } from '@midscene/web';
|
|
3
|
+
import { Size, Point } from '@midscene/core';
|
|
4
|
+
import { ElementInfo } from '@midscene/shared/extractor';
|
|
5
|
+
import { ADB } from 'appium-adb';
|
|
6
|
+
|
|
7
|
+
declare class Page implements AbstractPage {
|
|
8
|
+
private deviceId;
|
|
9
|
+
private screenSize;
|
|
10
|
+
private yadbPushed;
|
|
11
|
+
private deviceRatio;
|
|
12
|
+
private adbInitPromise;
|
|
13
|
+
pageType: string;
|
|
14
|
+
constructor({ deviceId }: {
|
|
15
|
+
deviceId: string;
|
|
16
|
+
});
|
|
17
|
+
private initAdb;
|
|
18
|
+
getAdb(): Promise<ADB>;
|
|
19
|
+
private execYadb;
|
|
20
|
+
getElementsInfo(): Promise<ElementInfo[]>;
|
|
21
|
+
getElementsNodeTree(): Promise<any>;
|
|
22
|
+
size(): Promise<Size>;
|
|
23
|
+
/**
|
|
24
|
+
* Convert logical coordinates to physical coordinates, handling device ratio
|
|
25
|
+
* @param x Logical X coordinate
|
|
26
|
+
* @param y Logical Y coordinate
|
|
27
|
+
* @returns Physical coordinate point
|
|
28
|
+
*/
|
|
29
|
+
private adjustCoordinates;
|
|
30
|
+
/**
|
|
31
|
+
* Convert physical coordinates to logical coordinates, handling device ratio
|
|
32
|
+
* @param x Physical X coordinate
|
|
33
|
+
* @param y Physical Y coordinate
|
|
34
|
+
* @returns Logical coordinate point
|
|
35
|
+
*/
|
|
36
|
+
private reverseAdjustCoordinates;
|
|
37
|
+
screenshotBase64(): Promise<string>;
|
|
38
|
+
get mouse(): {
|
|
39
|
+
click: (x: number, y: number) => Promise<void>;
|
|
40
|
+
wheel: (deltaX: number, deltaY: number) => Promise<void>;
|
|
41
|
+
move: (x: number, y: number) => Promise<void>;
|
|
42
|
+
drag: (from: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
}, to: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
}) => Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
get keyboard(): {
|
|
51
|
+
type: (text: string) => Promise<void>;
|
|
52
|
+
press: (action: {
|
|
53
|
+
key: string;
|
|
54
|
+
command?: string;
|
|
55
|
+
} | {
|
|
56
|
+
key: string;
|
|
57
|
+
command?: string;
|
|
58
|
+
}[]) => Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
clearInput(element: ElementInfo): Promise<void>;
|
|
61
|
+
url(): Promise<string>;
|
|
62
|
+
scrollUntilTop(startingPoint?: Point): Promise<void>;
|
|
63
|
+
scrollUntilBottom(startingPoint?: Point): Promise<void>;
|
|
64
|
+
scrollUntilLeft(startingPoint?: Point): Promise<void>;
|
|
65
|
+
scrollUntilRight(startingPoint?: Point): Promise<void>;
|
|
66
|
+
scrollUp(distance?: number, startingPoint?: Point): Promise<void>;
|
|
67
|
+
scrollDown(distance?: number, startingPoint?: Point): Promise<void>;
|
|
68
|
+
scrollLeft(distance?: number, startingPoint?: Point): Promise<void>;
|
|
69
|
+
scrollRight(distance?: number, startingPoint?: Point): Promise<void>;
|
|
70
|
+
private pushYadb;
|
|
71
|
+
private keyboardType;
|
|
72
|
+
private keyboardPress;
|
|
73
|
+
private keyboardPressAction;
|
|
74
|
+
private mouseClick;
|
|
75
|
+
private mouseMove;
|
|
76
|
+
private mouseDrag;
|
|
77
|
+
private mouseWheel;
|
|
78
|
+
destroy(): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { Page as AndroidPage };
|
package/dist/lib/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,16 +17,347 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var src_exports = {};
|
|
22
32
|
__export(src_exports, {
|
|
23
|
-
AndroidAgent: () =>
|
|
24
|
-
AndroidPage: () =>
|
|
33
|
+
AndroidAgent: () => import_web.PageAgent,
|
|
34
|
+
AndroidPage: () => Page
|
|
25
35
|
});
|
|
26
36
|
module.exports = __toCommonJS(src_exports);
|
|
27
|
-
var
|
|
37
|
+
var import_web = require("@midscene/web");
|
|
38
|
+
|
|
39
|
+
// src/page/index.ts
|
|
40
|
+
var import_node_fs = __toESM(require("fs"));
|
|
41
|
+
var import_node_path = __toESM(require("path"));
|
|
42
|
+
var import_utils = require("@midscene/core/utils");
|
|
43
|
+
var import_img = require("@midscene/shared/img");
|
|
44
|
+
var import_logger = require("@midscene/shared/logger");
|
|
45
|
+
var import_appium_adb = require("appium-adb");
|
|
46
|
+
var debugPage = (0, import_logger.getDebug)("android");
|
|
47
|
+
var Page = class {
|
|
48
|
+
constructor({ deviceId }) {
|
|
49
|
+
this.screenSize = null;
|
|
50
|
+
this.yadbPushed = false;
|
|
51
|
+
this.deviceRatio = 1;
|
|
52
|
+
this.pageType = "android";
|
|
53
|
+
this.deviceId = deviceId;
|
|
54
|
+
this.adbInitPromise = this.initAdb();
|
|
55
|
+
}
|
|
56
|
+
async initAdb() {
|
|
57
|
+
debugPage(`Initializing ADB with device ID: ${this.deviceId}`);
|
|
58
|
+
const adb = await import_appium_adb.ADB.createADB({
|
|
59
|
+
udid: this.deviceId,
|
|
60
|
+
adbExecTimeout: 6e4
|
|
61
|
+
});
|
|
62
|
+
debugPage("ADB initialized successfully");
|
|
63
|
+
return adb;
|
|
64
|
+
}
|
|
65
|
+
async getAdb() {
|
|
66
|
+
return this.adbInitPromise;
|
|
67
|
+
}
|
|
68
|
+
async execYadb(keyboardContent) {
|
|
69
|
+
await this.pushYadb();
|
|
70
|
+
const adb = await this.getAdb();
|
|
71
|
+
await adb.shell(
|
|
72
|
+
`app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
async getElementsInfo() {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
async getElementsNodeTree() {
|
|
79
|
+
return {
|
|
80
|
+
node: null,
|
|
81
|
+
children: []
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async size() {
|
|
85
|
+
if (this.screenSize) {
|
|
86
|
+
return this.screenSize;
|
|
87
|
+
}
|
|
88
|
+
const adb = await this.getAdb();
|
|
89
|
+
const screenSize = await adb.getScreenSize();
|
|
90
|
+
let width;
|
|
91
|
+
let height;
|
|
92
|
+
if (typeof screenSize === "string") {
|
|
93
|
+
const match = screenSize.match(/(\d+)x(\d+)/);
|
|
94
|
+
if (!match || match.length < 3) {
|
|
95
|
+
throw new Error(`Unable to parse screen size: ${screenSize}`);
|
|
96
|
+
}
|
|
97
|
+
width = Number.parseInt(match[1], 10);
|
|
98
|
+
height = Number.parseInt(match[2], 10);
|
|
99
|
+
} else if (typeof screenSize === "object" && screenSize !== null) {
|
|
100
|
+
const sizeObj = screenSize;
|
|
101
|
+
if ("width" in sizeObj && "height" in sizeObj) {
|
|
102
|
+
width = Number(sizeObj.width);
|
|
103
|
+
height = Number(sizeObj.height);
|
|
104
|
+
} else {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Invalid screen size object: ${JSON.stringify(screenSize)}`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
throw new Error(`Invalid screen size format: ${screenSize}`);
|
|
111
|
+
}
|
|
112
|
+
const densityNum = await adb.getScreenDensity();
|
|
113
|
+
this.deviceRatio = Number(densityNum) / 160;
|
|
114
|
+
const { x: logicalWidth, y: logicalHeight } = this.reverseAdjustCoordinates(
|
|
115
|
+
width,
|
|
116
|
+
height
|
|
117
|
+
);
|
|
118
|
+
this.screenSize = {
|
|
119
|
+
width: logicalWidth,
|
|
120
|
+
height: logicalHeight
|
|
121
|
+
};
|
|
122
|
+
return this.screenSize;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert logical coordinates to physical coordinates, handling device ratio
|
|
126
|
+
* @param x Logical X coordinate
|
|
127
|
+
* @param y Logical Y coordinate
|
|
128
|
+
* @returns Physical coordinate point
|
|
129
|
+
*/
|
|
130
|
+
adjustCoordinates(x, y) {
|
|
131
|
+
const ratio = this.deviceRatio;
|
|
132
|
+
return {
|
|
133
|
+
x: Math.round(x * ratio),
|
|
134
|
+
y: Math.round(y * ratio)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Convert physical coordinates to logical coordinates, handling device ratio
|
|
139
|
+
* @param x Physical X coordinate
|
|
140
|
+
* @param y Physical Y coordinate
|
|
141
|
+
* @returns Logical coordinate point
|
|
142
|
+
*/
|
|
143
|
+
reverseAdjustCoordinates(x, y) {
|
|
144
|
+
const ratio = this.deviceRatio;
|
|
145
|
+
return {
|
|
146
|
+
x: Math.round(x / ratio),
|
|
147
|
+
y: Math.round(y / ratio)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async screenshotBase64() {
|
|
151
|
+
debugPage("screenshotBase64 begin");
|
|
152
|
+
const { width, height } = await this.size();
|
|
153
|
+
const adb = await this.getAdb();
|
|
154
|
+
let screenshotBuffer;
|
|
155
|
+
try {
|
|
156
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
const screenshotPath = (0, import_utils.getTmpFile)("png");
|
|
159
|
+
await adb.shell("screencap -p /sdcard/screenshot.png");
|
|
160
|
+
await adb.pull("/sdcard/screenshot.png", screenshotPath);
|
|
161
|
+
screenshotBuffer = await import_node_fs.default.promises.readFile(screenshotPath);
|
|
162
|
+
}
|
|
163
|
+
const resizedScreenshotBuffer = await (0, import_img.resizeImg)(screenshotBuffer, {
|
|
164
|
+
width,
|
|
165
|
+
height
|
|
166
|
+
});
|
|
167
|
+
const result = `data:image/jpeg;base64,${resizedScreenshotBuffer.toString("base64")}`;
|
|
168
|
+
debugPage("screenshotBase64 end");
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
get mouse() {
|
|
172
|
+
return {
|
|
173
|
+
click: (x, y) => this.mouseClick(x, y),
|
|
174
|
+
wheel: (deltaX, deltaY) => this.mouseWheel(deltaX, deltaY),
|
|
175
|
+
move: (x, y) => this.mouseMove(x, y),
|
|
176
|
+
drag: (from, to) => this.mouseDrag(from, to)
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
get keyboard() {
|
|
180
|
+
return {
|
|
181
|
+
type: (text) => this.keyboardType(text),
|
|
182
|
+
press: (action) => this.keyboardPressAction(action)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async clearInput(element) {
|
|
186
|
+
if (!element) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
await this.pushYadb();
|
|
190
|
+
const adb = await this.getAdb();
|
|
191
|
+
await adb.shell(
|
|
192
|
+
'app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "~CLEAR~"'
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
async url() {
|
|
196
|
+
const adb = await this.getAdb();
|
|
197
|
+
const { appPackage, appActivity } = await adb.getFocusedPackageAndActivity();
|
|
198
|
+
return `${appPackage}/${appActivity}`;
|
|
199
|
+
}
|
|
200
|
+
async scrollUntilTop(startingPoint) {
|
|
201
|
+
if (startingPoint) {
|
|
202
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
203
|
+
}
|
|
204
|
+
await this.mouseWheel(0, 9999999, 100);
|
|
205
|
+
}
|
|
206
|
+
async scrollUntilBottom(startingPoint) {
|
|
207
|
+
if (startingPoint) {
|
|
208
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
209
|
+
}
|
|
210
|
+
await this.mouseWheel(0, -9999999, 100);
|
|
211
|
+
}
|
|
212
|
+
async scrollUntilLeft(startingPoint) {
|
|
213
|
+
if (startingPoint) {
|
|
214
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
215
|
+
}
|
|
216
|
+
await this.mouseWheel(9999999, 0, 100);
|
|
217
|
+
}
|
|
218
|
+
async scrollUntilRight(startingPoint) {
|
|
219
|
+
if (startingPoint) {
|
|
220
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
221
|
+
}
|
|
222
|
+
await this.mouseWheel(-9999999, 0, 100);
|
|
223
|
+
}
|
|
224
|
+
async scrollUp(distance, startingPoint) {
|
|
225
|
+
const { height } = await this.size();
|
|
226
|
+
const scrollDistance = distance || height * 0.7;
|
|
227
|
+
if (startingPoint) {
|
|
228
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
229
|
+
}
|
|
230
|
+
await this.mouseWheel(0, scrollDistance, 1e3);
|
|
231
|
+
}
|
|
232
|
+
async scrollDown(distance, startingPoint) {
|
|
233
|
+
const { height } = await this.size();
|
|
234
|
+
const scrollDistance = distance || height * 0.7;
|
|
235
|
+
if (startingPoint) {
|
|
236
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
237
|
+
}
|
|
238
|
+
await this.mouseWheel(0, -scrollDistance, 1e3);
|
|
239
|
+
}
|
|
240
|
+
async scrollLeft(distance, startingPoint) {
|
|
241
|
+
const { width } = await this.size();
|
|
242
|
+
const scrollDistance = distance || width * 0.7;
|
|
243
|
+
if (startingPoint) {
|
|
244
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
245
|
+
}
|
|
246
|
+
await this.mouseWheel(scrollDistance, 0, 1e3);
|
|
247
|
+
}
|
|
248
|
+
async scrollRight(distance, startingPoint) {
|
|
249
|
+
const { width } = await this.size();
|
|
250
|
+
const scrollDistance = distance || width * 0.7;
|
|
251
|
+
if (startingPoint) {
|
|
252
|
+
await this.mouse.move(startingPoint.left, startingPoint.top);
|
|
253
|
+
}
|
|
254
|
+
await this.mouseWheel(-scrollDistance, 0, 1e3);
|
|
255
|
+
}
|
|
256
|
+
async pushYadb() {
|
|
257
|
+
if (!this.yadbPushed) {
|
|
258
|
+
const adb = await this.getAdb();
|
|
259
|
+
const yadbBin = import_node_path.default.join(__dirname, "../../bin/yadb");
|
|
260
|
+
await adb.push(yadbBin, "/data/local/tmp");
|
|
261
|
+
this.yadbPushed = true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async keyboardType(text) {
|
|
265
|
+
if (!text)
|
|
266
|
+
return;
|
|
267
|
+
const adb = await this.getAdb();
|
|
268
|
+
const isChinese = /[\p{Script=Han}\p{sc=Hani}]/u.test(text);
|
|
269
|
+
if (!isChinese) {
|
|
270
|
+
await adb.inputText(text);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
await this.execYadb(text);
|
|
274
|
+
}
|
|
275
|
+
async keyboardPress(key) {
|
|
276
|
+
const keyCodeMap = {
|
|
277
|
+
Enter: 66,
|
|
278
|
+
Backspace: 67,
|
|
279
|
+
Tab: 61,
|
|
280
|
+
ArrowUp: 19,
|
|
281
|
+
ArrowDown: 20,
|
|
282
|
+
ArrowLeft: 21,
|
|
283
|
+
ArrowRight: 22,
|
|
284
|
+
Escape: 111,
|
|
285
|
+
Home: 3,
|
|
286
|
+
End: 123
|
|
287
|
+
};
|
|
288
|
+
const adb = await this.getAdb();
|
|
289
|
+
const keyCode = keyCodeMap[key];
|
|
290
|
+
if (keyCode !== void 0) {
|
|
291
|
+
await adb.keyevent(keyCode);
|
|
292
|
+
} else {
|
|
293
|
+
if (key.length === 1) {
|
|
294
|
+
const asciiCode = key.toUpperCase().charCodeAt(0);
|
|
295
|
+
if (asciiCode >= 65 && asciiCode <= 90) {
|
|
296
|
+
await adb.keyevent(asciiCode - 36);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async keyboardPressAction(action) {
|
|
302
|
+
if (Array.isArray(action)) {
|
|
303
|
+
for (const act of action) {
|
|
304
|
+
await this.keyboardPress(act.key);
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
await this.keyboardPress(action.key);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async mouseClick(x, y) {
|
|
311
|
+
await this.mouseMove(x, y);
|
|
312
|
+
const adb = await this.getAdb();
|
|
313
|
+
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
314
|
+
await adb.shell(`input tap ${adjustedX} ${adjustedY}`);
|
|
315
|
+
}
|
|
316
|
+
async mouseMove(x, y) {
|
|
317
|
+
return Promise.resolve();
|
|
318
|
+
}
|
|
319
|
+
async mouseDrag(from, to) {
|
|
320
|
+
const adb = await this.getAdb();
|
|
321
|
+
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
322
|
+
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
323
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} 300`);
|
|
324
|
+
}
|
|
325
|
+
async mouseWheel(deltaX, deltaY, duration = 1e3) {
|
|
326
|
+
const { width, height } = await this.size();
|
|
327
|
+
const n = 4;
|
|
328
|
+
const startX = deltaX < 0 ? (n - 1) * (width / n) : width / n;
|
|
329
|
+
const startY = deltaY < 0 ? (n - 1) * (height / n) : height / n;
|
|
330
|
+
const maxNegativeDeltaX = startX;
|
|
331
|
+
const maxPositiveDeltaX = (n - 1) * (width / n);
|
|
332
|
+
const maxNegativeDeltaY = startY;
|
|
333
|
+
const maxPositiveDeltaY = (n - 1) * (height / n);
|
|
334
|
+
deltaX = Math.max(-maxNegativeDeltaX, Math.min(deltaX, maxPositiveDeltaX));
|
|
335
|
+
deltaY = Math.max(-maxNegativeDeltaY, Math.min(deltaY, maxPositiveDeltaY));
|
|
336
|
+
const endX = startX + deltaX;
|
|
337
|
+
const endY = startY + deltaY;
|
|
338
|
+
const { x: adjustedStartX, y: adjustedStartY } = this.adjustCoordinates(
|
|
339
|
+
startX,
|
|
340
|
+
startY
|
|
341
|
+
);
|
|
342
|
+
const { x: adjustedEndX, y: adjustedEndY } = this.adjustCoordinates(
|
|
343
|
+
endX,
|
|
344
|
+
endY
|
|
345
|
+
);
|
|
346
|
+
const adb = await this.getAdb();
|
|
347
|
+
await adb.shell(
|
|
348
|
+
`input swipe ${adjustedStartX} ${adjustedStartY} ${adjustedEndX} ${adjustedEndY} ${duration}`
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
async destroy() {
|
|
352
|
+
try {
|
|
353
|
+
const adb = await this.getAdb();
|
|
354
|
+
await adb.shell("rm -f /sdcard/screenshot.png");
|
|
355
|
+
await adb.shell("rm -f /sdcard/window_dump.xml");
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error("Error during cleanup:", error);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
};
|
|
28
361
|
// Annotate the CommonJS export names for ESM import in node:
|
|
29
362
|
0 && (module.exports = {
|
|
30
363
|
AndroidAgent,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1,81 @@
|
|
|
1
|
-
|
|
1
|
+
import { AbstractPage } from '@midscene/web';
|
|
2
|
+
export { PageAgent as AndroidAgent } from '@midscene/web';
|
|
3
|
+
import { Size, Point } from '@midscene/core';
|
|
4
|
+
import { ElementInfo } from '@midscene/shared/extractor';
|
|
5
|
+
import { ADB } from 'appium-adb';
|
|
6
|
+
|
|
7
|
+
declare class Page implements AbstractPage {
|
|
8
|
+
private deviceId;
|
|
9
|
+
private screenSize;
|
|
10
|
+
private yadbPushed;
|
|
11
|
+
private deviceRatio;
|
|
12
|
+
private adbInitPromise;
|
|
13
|
+
pageType: string;
|
|
14
|
+
constructor({ deviceId }: {
|
|
15
|
+
deviceId: string;
|
|
16
|
+
});
|
|
17
|
+
private initAdb;
|
|
18
|
+
getAdb(): Promise<ADB>;
|
|
19
|
+
private execYadb;
|
|
20
|
+
getElementsInfo(): Promise<ElementInfo[]>;
|
|
21
|
+
getElementsNodeTree(): Promise<any>;
|
|
22
|
+
size(): Promise<Size>;
|
|
23
|
+
/**
|
|
24
|
+
* Convert logical coordinates to physical coordinates, handling device ratio
|
|
25
|
+
* @param x Logical X coordinate
|
|
26
|
+
* @param y Logical Y coordinate
|
|
27
|
+
* @returns Physical coordinate point
|
|
28
|
+
*/
|
|
29
|
+
private adjustCoordinates;
|
|
30
|
+
/**
|
|
31
|
+
* Convert physical coordinates to logical coordinates, handling device ratio
|
|
32
|
+
* @param x Physical X coordinate
|
|
33
|
+
* @param y Physical Y coordinate
|
|
34
|
+
* @returns Logical coordinate point
|
|
35
|
+
*/
|
|
36
|
+
private reverseAdjustCoordinates;
|
|
37
|
+
screenshotBase64(): Promise<string>;
|
|
38
|
+
get mouse(): {
|
|
39
|
+
click: (x: number, y: number) => Promise<void>;
|
|
40
|
+
wheel: (deltaX: number, deltaY: number) => Promise<void>;
|
|
41
|
+
move: (x: number, y: number) => Promise<void>;
|
|
42
|
+
drag: (from: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
}, to: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
}) => Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
get keyboard(): {
|
|
51
|
+
type: (text: string) => Promise<void>;
|
|
52
|
+
press: (action: {
|
|
53
|
+
key: string;
|
|
54
|
+
command?: string;
|
|
55
|
+
} | {
|
|
56
|
+
key: string;
|
|
57
|
+
command?: string;
|
|
58
|
+
}[]) => Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
clearInput(element: ElementInfo): Promise<void>;
|
|
61
|
+
url(): Promise<string>;
|
|
62
|
+
scrollUntilTop(startingPoint?: Point): Promise<void>;
|
|
63
|
+
scrollUntilBottom(startingPoint?: Point): Promise<void>;
|
|
64
|
+
scrollUntilLeft(startingPoint?: Point): Promise<void>;
|
|
65
|
+
scrollUntilRight(startingPoint?: Point): Promise<void>;
|
|
66
|
+
scrollUp(distance?: number, startingPoint?: Point): Promise<void>;
|
|
67
|
+
scrollDown(distance?: number, startingPoint?: Point): Promise<void>;
|
|
68
|
+
scrollLeft(distance?: number, startingPoint?: Point): Promise<void>;
|
|
69
|
+
scrollRight(distance?: number, startingPoint?: Point): Promise<void>;
|
|
70
|
+
private pushYadb;
|
|
71
|
+
private keyboardType;
|
|
72
|
+
private keyboardPress;
|
|
73
|
+
private keyboardPressAction;
|
|
74
|
+
private mouseClick;
|
|
75
|
+
private mouseMove;
|
|
76
|
+
private mouseDrag;
|
|
77
|
+
private mouseWheel;
|
|
78
|
+
destroy(): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { Page as AndroidPage };
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/android",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2-beta-20250401015137.0",
|
|
4
|
+
"description": "Android automation library for Midscene",
|
|
4
5
|
"main": "./dist/lib/index.js",
|
|
5
6
|
"types": "./dist/types/index.d.ts",
|
|
6
7
|
"files": [
|
|
7
|
-
"dist"
|
|
8
|
+
"dist",
|
|
9
|
+
"bin",
|
|
10
|
+
"README.md"
|
|
8
11
|
],
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
@@ -13,17 +16,23 @@
|
|
|
13
16
|
}
|
|
14
17
|
},
|
|
15
18
|
"dependencies": {
|
|
16
|
-
"
|
|
19
|
+
"appium-adb": "12.12.1",
|
|
20
|
+
"@midscene/web": "0.13.2-beta-20250401015137.0",
|
|
21
|
+
"@midscene/core": "0.13.2-beta-20250401015137.0",
|
|
22
|
+
"@midscene/shared": "0.13.2-beta-20250401015137.0"
|
|
17
23
|
},
|
|
18
24
|
"devDependencies": {
|
|
19
25
|
"@modern-js/module-tools": "2.60.6",
|
|
20
26
|
"@types/node": "^18.0.0",
|
|
21
|
-
"
|
|
27
|
+
"dotenv": "16.4.5",
|
|
28
|
+
"typescript": "^5.8.2",
|
|
29
|
+
"vitest": "3.0.5"
|
|
22
30
|
},
|
|
23
|
-
"
|
|
24
|
-
"license": "ISC",
|
|
25
|
-
"description": "",
|
|
31
|
+
"license": "MIT",
|
|
26
32
|
"scripts": {
|
|
27
|
-
"build": "modern build -c ./modern.config.ts"
|
|
33
|
+
"build": "modern build -c ./modern.config.ts",
|
|
34
|
+
"test": "vitest --run",
|
|
35
|
+
"test:u": "vitest --run -u",
|
|
36
|
+
"test:ai": "MIDSCENE_CACHE=true npm run test"
|
|
28
37
|
}
|
|
29
38
|
}
|