assistsx-js 0.0.2001 → 0.0.2003
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/AssistsX.d.ts +30 -9
- package/dist/AssistsX.js +41 -36
- package/dist/AssistsXAsync.d.ts +1 -1
- package/dist/AssistsXAsync.js +7 -4
- package/dist/Node.d.ts +6 -0
- package/dist/Node.js +11 -0
- package/dist/NodeAsync.d.ts +6 -0
- package/dist/NodeAsync.js +11 -0
- package/dist/Step.d.ts +32 -30
- package/dist/Step.js +81 -20
- package/dist/StepAsync.d.ts +0 -6
- package/dist/StepAsync.js +0 -11
- package/dist/Utils.d.ts +1 -0
- package/dist/Utils.js +12 -4
- package/package.json +1 -1
- package/src/AssistsX.ts +72 -41
- package/src/AssistsXAsync.ts +10 -4
- package/src/Node.ts +12 -0
- package/src/NodeAsync.ts +14 -1
- package/src/Step.ts +100 -44
- package/src/StepAsync.ts +0 -12
- package/src/Utils.ts +16 -7
package/dist/AssistsX.d.ts
CHANGED
|
@@ -5,6 +5,30 @@
|
|
|
5
5
|
import { Node } from "./Node";
|
|
6
6
|
import { CallResponse } from "./CallResponse";
|
|
7
7
|
import { Bounds } from "./Bounds";
|
|
8
|
+
/**
|
|
9
|
+
* 无障碍事件数据结构
|
|
10
|
+
*/
|
|
11
|
+
export interface AccessibilityEventData {
|
|
12
|
+
packageName: string;
|
|
13
|
+
className: string;
|
|
14
|
+
eventType: number;
|
|
15
|
+
action: number;
|
|
16
|
+
texts: string[];
|
|
17
|
+
node: Node;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 无障碍事件完整结构
|
|
21
|
+
*/
|
|
22
|
+
export interface AccessibilityEvent {
|
|
23
|
+
callbackId: string;
|
|
24
|
+
code: number;
|
|
25
|
+
data: AccessibilityEventData;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 无障碍事件监听器类型
|
|
30
|
+
*/
|
|
31
|
+
export type AccessibilityEventListener = (event: AccessibilityEvent) => void;
|
|
8
32
|
/**
|
|
9
33
|
* Web浮动窗口选项接口定义
|
|
10
34
|
*/
|
|
@@ -17,10 +41,8 @@ export interface WebFloatingWindowOptions {
|
|
|
17
41
|
maxHeight?: number;
|
|
18
42
|
initialCenter?: boolean;
|
|
19
43
|
}
|
|
20
|
-
export declare const callbacks:
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
export declare const accessibilityEventListeners: ((event: any) => void)[];
|
|
44
|
+
export declare const callbacks: Map<string, (data: string) => void>;
|
|
45
|
+
export declare const accessibilityEventListeners: AccessibilityEventListener[];
|
|
24
46
|
export declare class AssistsX {
|
|
25
47
|
/**
|
|
26
48
|
* 执行同步调用
|
|
@@ -182,7 +204,7 @@ export declare class AssistsX {
|
|
|
182
204
|
* @param className 类名
|
|
183
205
|
* @returns 父节点
|
|
184
206
|
*/
|
|
185
|
-
static findFirstParentByTags(className: string): Node;
|
|
207
|
+
static findFirstParentByTags(node: Node, className: string): Node;
|
|
186
208
|
/**
|
|
187
209
|
* 获取节点的所有子节点
|
|
188
210
|
* @param node 父节点
|
|
@@ -354,15 +376,14 @@ export declare class AssistsX {
|
|
|
354
376
|
/**
|
|
355
377
|
* 添加无障碍事件监听器
|
|
356
378
|
* @param listener 监听器函数
|
|
357
|
-
* @returns 监听器ID,用于移除监听器
|
|
358
379
|
*/
|
|
359
|
-
static addAccessibilityEventListener(listener:
|
|
380
|
+
static addAccessibilityEventListener(listener: AccessibilityEventListener): void;
|
|
360
381
|
/**
|
|
361
382
|
* 移除无障碍事件监听器
|
|
362
|
-
* @param
|
|
383
|
+
* @param listener 要移除的监听器函数
|
|
363
384
|
* @returns 是否移除成功
|
|
364
385
|
*/
|
|
365
|
-
static removeAccessibilityEventListener(
|
|
386
|
+
static removeAccessibilityEventListener(listener: AccessibilityEventListener): boolean;
|
|
366
387
|
/**
|
|
367
388
|
* 移除所有无障碍事件监听器
|
|
368
389
|
*/
|
package/dist/AssistsX.js
CHANGED
|
@@ -6,28 +6,47 @@ import { Node } from "./Node";
|
|
|
6
6
|
import { CallMethod } from "./CallMethod";
|
|
7
7
|
import { CallResponse } from "./CallResponse";
|
|
8
8
|
import { Bounds } from "./Bounds";
|
|
9
|
-
import { generateUUID } from "./Utils";
|
|
9
|
+
import { decodeBase64UTF8, generateUUID } from "./Utils";
|
|
10
10
|
// 回调函数存储对象
|
|
11
|
-
export const callbacks =
|
|
11
|
+
export const callbacks = new Map();
|
|
12
12
|
// 无障碍事件监听器存储
|
|
13
13
|
export const accessibilityEventListeners = [];
|
|
14
14
|
// 初始化全局回调函数
|
|
15
15
|
if (typeof window !== "undefined" && !window.assistsxCallback) {
|
|
16
16
|
window.assistsxCallback = (data) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
let callbackId;
|
|
18
|
+
try {
|
|
19
|
+
const json = decodeBase64UTF8(data);
|
|
20
|
+
const response = JSON.parse(json);
|
|
21
|
+
callbackId = response.callbackId;
|
|
22
|
+
if (callbackId) {
|
|
23
|
+
const callback = callbacks.get(callbackId);
|
|
24
|
+
if (callback) {
|
|
25
|
+
callback(json);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
console.log(e);
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
// 无论成功还是失败,都删除回调函数
|
|
34
|
+
if (callbackId) {
|
|
35
|
+
callbacks.delete(callbackId);
|
|
36
|
+
}
|
|
21
37
|
}
|
|
22
38
|
};
|
|
23
39
|
}
|
|
24
40
|
// 初始化全局无障碍事件函数
|
|
25
41
|
if (typeof window !== "undefined" && !window.onAccessibilityEvent) {
|
|
26
42
|
window.onAccessibilityEvent = (event) => {
|
|
27
|
-
//
|
|
43
|
+
// 通知所有注册的监听器,每个监听器都有独立的错误处理
|
|
28
44
|
accessibilityEventListeners.forEach((listener) => {
|
|
29
45
|
try {
|
|
30
|
-
|
|
46
|
+
//base64 decode
|
|
47
|
+
const decodedEvent = decodeBase64UTF8(event);
|
|
48
|
+
const parsedEvent = JSON.parse(decodedEvent);
|
|
49
|
+
listener(parsedEvent);
|
|
31
50
|
}
|
|
32
51
|
catch (error) {
|
|
33
52
|
console.error("Accessibility event listener error:", error);
|
|
@@ -72,12 +91,14 @@ export class AssistsX {
|
|
|
72
91
|
callbackId: uuid,
|
|
73
92
|
};
|
|
74
93
|
const promise = new Promise((resolve) => {
|
|
75
|
-
callbacks
|
|
94
|
+
callbacks.set(uuid, (data) => {
|
|
76
95
|
resolve(data);
|
|
77
|
-
};
|
|
96
|
+
});
|
|
78
97
|
setTimeout(() => {
|
|
98
|
+
// 超时后删除回调函数
|
|
99
|
+
callbacks.delete(uuid);
|
|
79
100
|
resolve(new CallResponse(0, null, uuid));
|
|
80
|
-
},
|
|
101
|
+
}, 1000 * 30);
|
|
81
102
|
});
|
|
82
103
|
const result = window.assistsx.call(JSON.stringify(params));
|
|
83
104
|
const promiseResult = await promise;
|
|
@@ -301,9 +322,10 @@ export class AssistsX {
|
|
|
301
322
|
* @param className 类名
|
|
302
323
|
* @returns 父节点
|
|
303
324
|
*/
|
|
304
|
-
static findFirstParentByTags(className) {
|
|
325
|
+
static findFirstParentByTags(node, className) {
|
|
305
326
|
const response = this.call(CallMethod.findFirstParentByTags, {
|
|
306
327
|
args: { className },
|
|
328
|
+
node,
|
|
307
329
|
});
|
|
308
330
|
return Node.create(response.getDataOrDefault("{}"));
|
|
309
331
|
}
|
|
@@ -563,37 +585,20 @@ export class AssistsX {
|
|
|
563
585
|
/**
|
|
564
586
|
* 添加无障碍事件监听器
|
|
565
587
|
* @param listener 监听器函数
|
|
566
|
-
* @returns 监听器ID,用于移除监听器
|
|
567
588
|
*/
|
|
568
589
|
static addAccessibilityEventListener(listener) {
|
|
569
|
-
|
|
570
|
-
const wrappedListener = (event) => {
|
|
571
|
-
try {
|
|
572
|
-
listener(event);
|
|
573
|
-
}
|
|
574
|
-
catch (error) {
|
|
575
|
-
console.error("Accessibility event listener error:", error);
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
// 将监听器包装并存储,使用ID作为键
|
|
579
|
-
accessibilityEventListeners[listenerId] = wrappedListener;
|
|
580
|
-
accessibilityEventListeners.push(wrappedListener);
|
|
581
|
-
return listenerId;
|
|
590
|
+
accessibilityEventListeners.push(listener);
|
|
582
591
|
}
|
|
583
592
|
/**
|
|
584
593
|
* 移除无障碍事件监听器
|
|
585
|
-
* @param
|
|
594
|
+
* @param listener 要移除的监听器函数
|
|
586
595
|
* @returns 是否移除成功
|
|
587
596
|
*/
|
|
588
|
-
static removeAccessibilityEventListener(
|
|
589
|
-
const
|
|
590
|
-
if (
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
accessibilityEventListeners.splice(index, 1);
|
|
594
|
-
delete accessibilityEventListeners[listenerId];
|
|
595
|
-
return true;
|
|
596
|
-
}
|
|
597
|
+
static removeAccessibilityEventListener(listener) {
|
|
598
|
+
const index = accessibilityEventListeners.indexOf(listener);
|
|
599
|
+
if (index > -1) {
|
|
600
|
+
accessibilityEventListeners.splice(index, 1);
|
|
601
|
+
return true;
|
|
597
602
|
}
|
|
598
603
|
return false;
|
|
599
604
|
}
|
package/dist/AssistsXAsync.d.ts
CHANGED
|
@@ -152,7 +152,7 @@ export declare class AssistsXAsync {
|
|
|
152
152
|
* @param className 类名
|
|
153
153
|
* @returns 父节点
|
|
154
154
|
*/
|
|
155
|
-
static findFirstParentByTags(className: string): Promise<Node>;
|
|
155
|
+
static findFirstParentByTags(node: Node, className: string): Promise<Node>;
|
|
156
156
|
/**
|
|
157
157
|
* 获取节点的所有子节点
|
|
158
158
|
* @param node 父节点
|
package/dist/AssistsXAsync.js
CHANGED
|
@@ -25,12 +25,14 @@ export class AssistsXAsync {
|
|
|
25
25
|
callbackId: uuid,
|
|
26
26
|
};
|
|
27
27
|
const promise = new Promise((resolve) => {
|
|
28
|
-
callbacks
|
|
28
|
+
callbacks.set(uuid, (data) => {
|
|
29
29
|
resolve(data);
|
|
30
|
-
};
|
|
30
|
+
});
|
|
31
31
|
setTimeout(() => {
|
|
32
|
+
// 超时后删除回调函数
|
|
33
|
+
callbacks.delete(uuid);
|
|
32
34
|
resolve(new CallResponse(0, null, uuid));
|
|
33
|
-
},
|
|
35
|
+
}, 1000 * 30);
|
|
34
36
|
});
|
|
35
37
|
const result = window.assistsxAsync.call(JSON.stringify(params));
|
|
36
38
|
const promiseResult = await promise;
|
|
@@ -258,9 +260,10 @@ export class AssistsXAsync {
|
|
|
258
260
|
* @param className 类名
|
|
259
261
|
* @returns 父节点
|
|
260
262
|
*/
|
|
261
|
-
static async findFirstParentByTags(className) {
|
|
263
|
+
static async findFirstParentByTags(node, className) {
|
|
262
264
|
const response = await this.asyncCall(CallMethod.findFirstParentByTags, {
|
|
263
265
|
args: { className },
|
|
266
|
+
node,
|
|
264
267
|
});
|
|
265
268
|
return Node.create(response.getDataOrDefault("{}"));
|
|
266
269
|
}
|
package/dist/Node.d.ts
CHANGED
|
@@ -57,6 +57,12 @@ export declare class Node {
|
|
|
57
57
|
stepId: string | undefined;
|
|
58
58
|
});
|
|
59
59
|
get async(): NodeAsync;
|
|
60
|
+
/**
|
|
61
|
+
* 查找第一个匹配标签的父节点
|
|
62
|
+
* @param className 类名
|
|
63
|
+
* @returns 父节点
|
|
64
|
+
*/
|
|
65
|
+
findFirstParentByTags(className: string): Node;
|
|
60
66
|
/**
|
|
61
67
|
* 对节点执行点击手势
|
|
62
68
|
* @param offsetX X轴偏移
|
package/dist/Node.js
CHANGED
|
@@ -21,6 +21,17 @@ export class Node {
|
|
|
21
21
|
get async() {
|
|
22
22
|
return new NodeAsync(this);
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* 查找第一个匹配标签的父节点
|
|
26
|
+
* @param className 类名
|
|
27
|
+
* @returns 父节点
|
|
28
|
+
*/
|
|
29
|
+
findFirstParentByTags(className) {
|
|
30
|
+
Step.assert(this.stepId);
|
|
31
|
+
const node = AssistsX.findFirstParentByTags(this, className);
|
|
32
|
+
Step.assert(this.stepId);
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
24
35
|
/**
|
|
25
36
|
* 对节点执行点击手势
|
|
26
37
|
* @param offsetX X轴偏移
|
package/dist/NodeAsync.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export declare class NodeAsync {
|
|
|
11
11
|
* @param node Node实例
|
|
12
12
|
*/
|
|
13
13
|
constructor(node: Node);
|
|
14
|
+
/**
|
|
15
|
+
* 查找第一个匹配标签的父节点
|
|
16
|
+
* @param className 类名
|
|
17
|
+
* @returns 父节点
|
|
18
|
+
*/
|
|
19
|
+
findFirstParentByTags(className: string): Promise<Node>;
|
|
14
20
|
/**
|
|
15
21
|
* 对节点执行点击手势
|
|
16
22
|
* @param offsetX X轴偏移
|
package/dist/NodeAsync.js
CHANGED
|
@@ -9,6 +9,17 @@ export class NodeAsync {
|
|
|
9
9
|
constructor(node) {
|
|
10
10
|
this.node = node;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* 查找第一个匹配标签的父节点
|
|
14
|
+
* @param className 类名
|
|
15
|
+
* @returns 父节点
|
|
16
|
+
*/
|
|
17
|
+
async findFirstParentByTags(className) {
|
|
18
|
+
Step.assert(this.node.stepId);
|
|
19
|
+
const node = await AssistsXAsync.findFirstParentByTags(this.node, className);
|
|
20
|
+
Step.assert(this.node.stepId);
|
|
21
|
+
return node;
|
|
22
|
+
}
|
|
12
23
|
/**
|
|
13
24
|
* 对节点执行点击手势
|
|
14
25
|
* @param offsetX X轴偏移
|
package/dist/Step.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Node } from "./Node";
|
|
2
2
|
import { StepAsync } from "./StepAsync";
|
|
3
|
+
export type StepResult = Step | undefined;
|
|
4
|
+
export type StepImpl = (step: Step) => Promise<StepResult>;
|
|
5
|
+
export type StepInterceptor = (step: Step) => StepResult | Promise<StepResult>;
|
|
3
6
|
export declare class Step {
|
|
4
7
|
static delayMsDefault: number;
|
|
5
8
|
static readonly repeatCountInfinite: number;
|
|
@@ -9,6 +12,10 @@ export declare class Step {
|
|
|
9
12
|
* 当前执行步骤的ID
|
|
10
13
|
*/
|
|
11
14
|
private static _stepId;
|
|
15
|
+
/**
|
|
16
|
+
* 步骤拦截器列表
|
|
17
|
+
*/
|
|
18
|
+
private static _interceptors;
|
|
12
19
|
/**
|
|
13
20
|
* 运行步骤实现
|
|
14
21
|
* @param impl 步骤实现函数
|
|
@@ -16,12 +23,9 @@ export declare class Step {
|
|
|
16
23
|
* @param data 步骤数据
|
|
17
24
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
18
25
|
*/
|
|
19
|
-
static run(impl:
|
|
26
|
+
static run(impl: StepImpl, { tag, data, delayMs, }?: {
|
|
20
27
|
tag?: string | undefined;
|
|
21
28
|
data?: any | undefined;
|
|
22
|
-
backupSteps?: {
|
|
23
|
-
[key: string]: (step: Step) => Promise<Step | undefined>;
|
|
24
|
-
} | undefined;
|
|
25
29
|
delayMs?: number;
|
|
26
30
|
}): Promise<Step>;
|
|
27
31
|
/**
|
|
@@ -43,6 +47,25 @@ export declare class Step {
|
|
|
43
47
|
* 停止当前步骤执行
|
|
44
48
|
*/
|
|
45
49
|
static stop(): void;
|
|
50
|
+
/**
|
|
51
|
+
* 添加步骤拦截器
|
|
52
|
+
* @param interceptor 拦截器函数
|
|
53
|
+
*/
|
|
54
|
+
static addInterceptor(interceptor: StepInterceptor): void;
|
|
55
|
+
/**
|
|
56
|
+
* 移除步骤拦截器
|
|
57
|
+
* @param interceptor 要移除的拦截器函数
|
|
58
|
+
*/
|
|
59
|
+
static removeInterceptor(interceptor: StepInterceptor): void;
|
|
60
|
+
/**
|
|
61
|
+
* 清空所有拦截器
|
|
62
|
+
*/
|
|
63
|
+
static clearInterceptors(): void;
|
|
64
|
+
/**
|
|
65
|
+
* 获取所有拦截器
|
|
66
|
+
* @returns 拦截器数组
|
|
67
|
+
*/
|
|
68
|
+
static getInterceptors(): StepInterceptor[];
|
|
46
69
|
/**
|
|
47
70
|
* 步骤ID
|
|
48
71
|
*/
|
|
@@ -70,13 +93,7 @@ export declare class Step {
|
|
|
70
93
|
/**
|
|
71
94
|
* 步骤实现函数
|
|
72
95
|
*/
|
|
73
|
-
impl:
|
|
74
|
-
/**
|
|
75
|
-
* 备份步骤,可用于在指定的步骤中转向其他步骤
|
|
76
|
-
*/
|
|
77
|
-
backupSteps: {
|
|
78
|
-
[key: string]: (step: Step) => Promise<Step | undefined>;
|
|
79
|
-
} | undefined;
|
|
96
|
+
impl: StepImpl;
|
|
80
97
|
/**
|
|
81
98
|
* 构造函数
|
|
82
99
|
* @param stepId 步骤ID
|
|
@@ -85,14 +102,11 @@ export declare class Step {
|
|
|
85
102
|
* @param data 步骤数据
|
|
86
103
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
87
104
|
*/
|
|
88
|
-
constructor({ stepId, impl, tag, data,
|
|
105
|
+
constructor({ stepId, impl, tag, data, delayMs, repeatCountMax, }: {
|
|
89
106
|
stepId: string;
|
|
90
|
-
impl:
|
|
107
|
+
impl: StepImpl;
|
|
91
108
|
tag?: string | undefined;
|
|
92
109
|
data?: any | undefined;
|
|
93
|
-
backupSteps?: {
|
|
94
|
-
[key: string]: (step: Step) => Promise<Step | undefined>;
|
|
95
|
-
} | undefined;
|
|
96
110
|
delayMs?: number;
|
|
97
111
|
repeatCountMax?: number;
|
|
98
112
|
});
|
|
@@ -105,12 +119,9 @@ export declare class Step {
|
|
|
105
119
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
106
120
|
* @returns 新的步骤实例
|
|
107
121
|
*/
|
|
108
|
-
next(impl:
|
|
122
|
+
next(impl: StepImpl, { tag, data, delayMs, repeatCountMax, }?: {
|
|
109
123
|
tag?: string | undefined;
|
|
110
124
|
data?: any | undefined;
|
|
111
|
-
backupSteps?: {
|
|
112
|
-
[key: string]: (step: Step) => Promise<Step | undefined>;
|
|
113
|
-
} | undefined;
|
|
114
125
|
delayMs?: number;
|
|
115
126
|
repeatCountMax?: number;
|
|
116
127
|
}): Step;
|
|
@@ -122,13 +133,10 @@ export declare class Step {
|
|
|
122
133
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
123
134
|
* @returns 当前步骤实例
|
|
124
135
|
*/
|
|
125
|
-
repeat({ stepId, tag, data,
|
|
136
|
+
repeat({ stepId, tag, data, delayMs, repeatCountMax, }?: {
|
|
126
137
|
stepId?: string;
|
|
127
138
|
tag?: string | undefined;
|
|
128
139
|
data?: any | undefined;
|
|
129
|
-
backupSteps?: {
|
|
130
|
-
[key: string]: (step: Step) => Promise<Step | undefined>;
|
|
131
|
-
} | undefined;
|
|
132
140
|
delayMs?: number;
|
|
133
141
|
repeatCountMax?: number;
|
|
134
142
|
}): Step;
|
|
@@ -239,12 +247,6 @@ export declare class Step {
|
|
|
239
247
|
* @returns 文本数组
|
|
240
248
|
*/
|
|
241
249
|
getAllText(): string[];
|
|
242
|
-
/**
|
|
243
|
-
* 查找第一个匹配标签的父节点
|
|
244
|
-
* @param className 类名
|
|
245
|
-
* @returns 父节点
|
|
246
|
-
*/
|
|
247
|
-
findFirstParentByTags(className: string): Node;
|
|
248
250
|
/**
|
|
249
251
|
* 执行点击手势
|
|
250
252
|
* @param x 横坐标
|
package/dist/Step.js
CHANGED
|
@@ -15,7 +15,7 @@ export class Step {
|
|
|
15
15
|
* @param data 步骤数据
|
|
16
16
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
17
17
|
*/
|
|
18
|
-
static async run(impl, { tag, data,
|
|
18
|
+
static async run(impl, { tag, data, delayMs = Step.delayMsDefault, } = {}) {
|
|
19
19
|
var _a;
|
|
20
20
|
const stepStore = useStepStore();
|
|
21
21
|
let implnName = impl.name;
|
|
@@ -30,7 +30,6 @@ export class Step {
|
|
|
30
30
|
impl,
|
|
31
31
|
tag,
|
|
32
32
|
data,
|
|
33
|
-
backupSteps,
|
|
34
33
|
delayMs,
|
|
35
34
|
});
|
|
36
35
|
while (true) {
|
|
@@ -46,7 +45,49 @@ export class Step {
|
|
|
46
45
|
if (Step.showLog) {
|
|
47
46
|
console.log(`执行步骤${implnName},重复次数${currentStep.repeatCount}`);
|
|
48
47
|
}
|
|
49
|
-
|
|
48
|
+
// 执行拦截器
|
|
49
|
+
let interceptedStep = undefined;
|
|
50
|
+
for (const interceptor of this._interceptors) {
|
|
51
|
+
try {
|
|
52
|
+
const result = await interceptor(currentStep);
|
|
53
|
+
if (result !== undefined) {
|
|
54
|
+
interceptedStep = result;
|
|
55
|
+
if (Step.showLog) {
|
|
56
|
+
console.log(`步骤${implnName}被拦截器拦截,执行拦截后的步骤`);
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
if (Step.showLog) {
|
|
63
|
+
console.error(`拦截器执行出错`, e);
|
|
64
|
+
}
|
|
65
|
+
// 拦截器出错不影响主流程,继续执行原步骤
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 如果被拦截,执行拦截后的步骤,否则执行原步骤
|
|
69
|
+
if (interceptedStep !== undefined) {
|
|
70
|
+
// 执行拦截后的步骤,需要处理延迟和重复次数
|
|
71
|
+
const stepToExecute = interceptedStep;
|
|
72
|
+
// 如果拦截后的步骤有延迟时间,先执行延迟
|
|
73
|
+
if (stepToExecute.delayMs) {
|
|
74
|
+
if (Step.showLog) {
|
|
75
|
+
console.log(`拦截步骤延迟${stepToExecute.delayMs}毫秒`);
|
|
76
|
+
}
|
|
77
|
+
await stepToExecute.delay(stepToExecute.delayMs);
|
|
78
|
+
Step.assert(stepToExecute.stepId);
|
|
79
|
+
}
|
|
80
|
+
// 打印拦截步骤的执行信息
|
|
81
|
+
const interceptedImplName = stepToExecute.impl.name;
|
|
82
|
+
if (Step.showLog) {
|
|
83
|
+
console.log(`执行拦截步骤${interceptedImplName},重复次数${stepToExecute.repeatCount}`);
|
|
84
|
+
}
|
|
85
|
+
// 执行拦截后的步骤
|
|
86
|
+
nextStep = await stepToExecute.impl(stepToExecute);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
nextStep = await currentStep.impl(currentStep);
|
|
90
|
+
}
|
|
50
91
|
if (currentStep.repeatCountMax > Step.repeatCountInfinite &&
|
|
51
92
|
currentStep.repeatCount > currentStep.repeatCountMax) {
|
|
52
93
|
if (Step.showLog) {
|
|
@@ -114,6 +155,36 @@ export class Step {
|
|
|
114
155
|
static stop() {
|
|
115
156
|
this._stepId = undefined;
|
|
116
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* 添加步骤拦截器
|
|
160
|
+
* @param interceptor 拦截器函数
|
|
161
|
+
*/
|
|
162
|
+
static addInterceptor(interceptor) {
|
|
163
|
+
this._interceptors.push(interceptor);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 移除步骤拦截器
|
|
167
|
+
* @param interceptor 要移除的拦截器函数
|
|
168
|
+
*/
|
|
169
|
+
static removeInterceptor(interceptor) {
|
|
170
|
+
const index = this._interceptors.indexOf(interceptor);
|
|
171
|
+
if (index > -1) {
|
|
172
|
+
this._interceptors.splice(index, 1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 清空所有拦截器
|
|
177
|
+
*/
|
|
178
|
+
static clearInterceptors() {
|
|
179
|
+
this._interceptors = [];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 获取所有拦截器
|
|
183
|
+
* @returns 拦截器数组
|
|
184
|
+
*/
|
|
185
|
+
static getInterceptors() {
|
|
186
|
+
return [...this._interceptors];
|
|
187
|
+
}
|
|
117
188
|
/**
|
|
118
189
|
* 构造函数
|
|
119
190
|
* @param stepId 步骤ID
|
|
@@ -122,7 +193,7 @@ export class Step {
|
|
|
122
193
|
* @param data 步骤数据
|
|
123
194
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
124
195
|
*/
|
|
125
|
-
constructor({ stepId, impl, tag, data,
|
|
196
|
+
constructor({ stepId, impl, tag, data, delayMs = Step.delayMsDefault, repeatCountMax = Step.repeatCountMaxDefault, }) {
|
|
126
197
|
/**
|
|
127
198
|
* 步骤ID
|
|
128
199
|
*/
|
|
@@ -143,7 +214,6 @@ export class Step {
|
|
|
143
214
|
this.stepId = stepId;
|
|
144
215
|
this.data = data;
|
|
145
216
|
this.impl = impl;
|
|
146
|
-
this.backupSteps = backupSteps;
|
|
147
217
|
this.delayMs = delayMs;
|
|
148
218
|
this.repeatCountMax = repeatCountMax;
|
|
149
219
|
}
|
|
@@ -158,14 +228,13 @@ export class Step {
|
|
|
158
228
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
159
229
|
* @returns 新的步骤实例
|
|
160
230
|
*/
|
|
161
|
-
next(impl, { tag, data,
|
|
231
|
+
next(impl, { tag, data, delayMs = Step.delayMsDefault, repeatCountMax = Step.repeatCountMaxDefault, } = {}) {
|
|
162
232
|
Step.assert(this.stepId);
|
|
163
233
|
return new Step({
|
|
164
234
|
stepId: this.stepId,
|
|
165
235
|
impl,
|
|
166
236
|
tag,
|
|
167
237
|
data: data !== null && data !== void 0 ? data : this.data,
|
|
168
|
-
backupSteps: backupSteps !== null && backupSteps !== void 0 ? backupSteps : this.backupSteps,
|
|
169
238
|
delayMs,
|
|
170
239
|
repeatCountMax,
|
|
171
240
|
});
|
|
@@ -178,13 +247,12 @@ export class Step {
|
|
|
178
247
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
179
248
|
* @returns 当前步骤实例
|
|
180
249
|
*/
|
|
181
|
-
repeat({ stepId = this.stepId, tag = this.tag, data = this.data,
|
|
250
|
+
repeat({ stepId = this.stepId, tag = this.tag, data = this.data, delayMs = this.delayMs, repeatCountMax = this.repeatCountMax, } = {}) {
|
|
182
251
|
Step.assert(this.stepId);
|
|
183
252
|
this.repeatCount++;
|
|
184
253
|
this.stepId = stepId;
|
|
185
254
|
this.tag = tag;
|
|
186
255
|
this.data = data;
|
|
187
|
-
this.backupSteps = backupSteps;
|
|
188
256
|
this.delayMs = delayMs;
|
|
189
257
|
this.repeatCountMax = repeatCountMax;
|
|
190
258
|
return this;
|
|
@@ -370,17 +438,6 @@ export class Step {
|
|
|
370
438
|
Step.assert(this.stepId);
|
|
371
439
|
return texts;
|
|
372
440
|
}
|
|
373
|
-
/**
|
|
374
|
-
* 查找第一个匹配标签的父节点
|
|
375
|
-
* @param className 类名
|
|
376
|
-
* @returns 父节点
|
|
377
|
-
*/
|
|
378
|
-
findFirstParentByTags(className) {
|
|
379
|
-
Step.assert(this.stepId);
|
|
380
|
-
const node = AssistsX.findFirstParentByTags(className);
|
|
381
|
-
Step.assert(this.stepId);
|
|
382
|
-
return node;
|
|
383
|
-
}
|
|
384
441
|
/**
|
|
385
442
|
* 执行点击手势
|
|
386
443
|
* @param x 横坐标
|
|
@@ -488,3 +545,7 @@ Step.showLog = false;
|
|
|
488
545
|
* 当前执行步骤的ID
|
|
489
546
|
*/
|
|
490
547
|
Step._stepId = undefined;
|
|
548
|
+
/**
|
|
549
|
+
* 步骤拦截器列表
|
|
550
|
+
*/
|
|
551
|
+
Step._interceptors = [];
|
package/dist/StepAsync.d.ts
CHANGED
|
@@ -102,12 +102,6 @@ export declare class StepAsync {
|
|
|
102
102
|
* @returns 文本数组
|
|
103
103
|
*/
|
|
104
104
|
getAllText(): Promise<string[]>;
|
|
105
|
-
/**
|
|
106
|
-
* 查找第一个匹配标签的父节点
|
|
107
|
-
* @param className 类名
|
|
108
|
-
* @returns 父节点
|
|
109
|
-
*/
|
|
110
|
-
findFirstParentByTags(className: string): Promise<Node>;
|
|
111
105
|
/**
|
|
112
106
|
* 执行点击手势
|
|
113
107
|
* @param x 横坐标
|
package/dist/StepAsync.js
CHANGED
|
@@ -163,17 +163,6 @@ export class StepAsync {
|
|
|
163
163
|
Step.assert(this.step.stepId);
|
|
164
164
|
return texts;
|
|
165
165
|
}
|
|
166
|
-
/**
|
|
167
|
-
* 查找第一个匹配标签的父节点
|
|
168
|
-
* @param className 类名
|
|
169
|
-
* @returns 父节点
|
|
170
|
-
*/
|
|
171
|
-
async findFirstParentByTags(className) {
|
|
172
|
-
Step.assert(this.step.stepId);
|
|
173
|
-
const node = await AssistsXAsync.findFirstParentByTags(className);
|
|
174
|
-
Step.assert(this.step.stepId);
|
|
175
|
-
return node;
|
|
176
|
-
}
|
|
177
166
|
/**
|
|
178
167
|
* 执行点击手势
|
|
179
168
|
* @param x 横坐标
|
package/dist/Utils.d.ts
CHANGED
package/dist/Utils.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
// 导出工具函数
|
|
2
2
|
export function sleep(ms) {
|
|
3
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
3
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
4
|
}
|
|
5
5
|
// 生成UUID
|
|
6
6
|
export function generateUUID() {
|
|
7
|
-
return
|
|
8
|
-
const r = Math.random() * 16 | 0;
|
|
9
|
-
const v = c ===
|
|
7
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
8
|
+
const r = (Math.random() * 16) | 0;
|
|
9
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
10
10
|
return v.toString(16);
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
+
export function decodeBase64UTF8(base64) {
|
|
14
|
+
const binary = atob(base64);
|
|
15
|
+
const bytes = new Uint8Array(binary.length);
|
|
16
|
+
for (let i = 0; i < binary.length; i++) {
|
|
17
|
+
bytes[i] = binary.charCodeAt(i);
|
|
18
|
+
}
|
|
19
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
20
|
+
}
|
package/package.json
CHANGED
package/src/AssistsX.ts
CHANGED
|
@@ -6,7 +6,34 @@ import { Node } from "./Node";
|
|
|
6
6
|
import { CallMethod } from "./CallMethod";
|
|
7
7
|
import { CallResponse } from "./CallResponse";
|
|
8
8
|
import { Bounds } from "./Bounds";
|
|
9
|
-
import { generateUUID } from "./Utils";
|
|
9
|
+
import { decodeBase64UTF8, generateUUID } from "./Utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 无障碍事件数据结构
|
|
13
|
+
*/
|
|
14
|
+
export interface AccessibilityEventData {
|
|
15
|
+
packageName: string;
|
|
16
|
+
className: string;
|
|
17
|
+
eventType: number;
|
|
18
|
+
action: number;
|
|
19
|
+
texts: string[];
|
|
20
|
+
node: Node;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 无障碍事件完整结构
|
|
25
|
+
*/
|
|
26
|
+
export interface AccessibilityEvent {
|
|
27
|
+
callbackId: string;
|
|
28
|
+
code: number;
|
|
29
|
+
data: AccessibilityEventData;
|
|
30
|
+
message: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 无障碍事件监听器类型
|
|
35
|
+
*/
|
|
36
|
+
export type AccessibilityEventListener = (event: AccessibilityEvent) => void;
|
|
10
37
|
|
|
11
38
|
/**
|
|
12
39
|
* Web浮动窗口选项接口定义
|
|
@@ -22,29 +49,46 @@ export interface WebFloatingWindowOptions {
|
|
|
22
49
|
}
|
|
23
50
|
|
|
24
51
|
// 回调函数存储对象
|
|
25
|
-
export const callbacks:
|
|
52
|
+
export const callbacks: Map<string, (data: string) => void> = new Map();
|
|
26
53
|
|
|
27
54
|
// 无障碍事件监听器存储
|
|
28
|
-
export const accessibilityEventListeners:
|
|
55
|
+
export const accessibilityEventListeners: AccessibilityEventListener[] = [];
|
|
29
56
|
|
|
30
57
|
// 初始化全局回调函数
|
|
31
58
|
if (typeof window !== "undefined" && !window.assistsxCallback) {
|
|
32
59
|
window.assistsxCallback = (data: string) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
let callbackId: string | undefined;
|
|
61
|
+
try {
|
|
62
|
+
const json = decodeBase64UTF8(data);
|
|
63
|
+
const response = JSON.parse(json);
|
|
64
|
+
callbackId = response.callbackId;
|
|
65
|
+
if (callbackId) {
|
|
66
|
+
const callback = callbacks.get(callbackId);
|
|
67
|
+
if (callback) {
|
|
68
|
+
callback(json);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (e) {
|
|
72
|
+
console.log(e);
|
|
73
|
+
} finally {
|
|
74
|
+
// 无论成功还是失败,都删除回调函数
|
|
75
|
+
if (callbackId) {
|
|
76
|
+
callbacks.delete(callbackId);
|
|
77
|
+
}
|
|
37
78
|
}
|
|
38
79
|
};
|
|
39
80
|
}
|
|
40
81
|
|
|
41
82
|
// 初始化全局无障碍事件函数
|
|
42
83
|
if (typeof window !== "undefined" && !window.onAccessibilityEvent) {
|
|
43
|
-
window.onAccessibilityEvent = (event:
|
|
44
|
-
//
|
|
84
|
+
window.onAccessibilityEvent = (event: string) => {
|
|
85
|
+
// 通知所有注册的监听器,每个监听器都有独立的错误处理
|
|
45
86
|
accessibilityEventListeners.forEach((listener) => {
|
|
46
87
|
try {
|
|
47
|
-
|
|
88
|
+
//base64 decode
|
|
89
|
+
const decodedEvent = decodeBase64UTF8(event);
|
|
90
|
+
const parsedEvent: AccessibilityEvent = JSON.parse(decodedEvent);
|
|
91
|
+
listener(parsedEvent);
|
|
48
92
|
} catch (error) {
|
|
49
93
|
console.error("Accessibility event listener error:", error);
|
|
50
94
|
}
|
|
@@ -100,12 +144,14 @@ export class AssistsX {
|
|
|
100
144
|
callbackId: uuid,
|
|
101
145
|
};
|
|
102
146
|
const promise = new Promise((resolve) => {
|
|
103
|
-
callbacks
|
|
147
|
+
callbacks.set(uuid, (data: string) => {
|
|
104
148
|
resolve(data);
|
|
105
|
-
};
|
|
149
|
+
});
|
|
106
150
|
setTimeout(() => {
|
|
151
|
+
// 超时后删除回调函数
|
|
152
|
+
callbacks.delete(uuid);
|
|
107
153
|
resolve(new CallResponse(0, null, uuid));
|
|
108
|
-
},
|
|
154
|
+
}, 1000 * 30);
|
|
109
155
|
});
|
|
110
156
|
const result = window.assistsx.call(JSON.stringify(params));
|
|
111
157
|
const promiseResult = await promise;
|
|
@@ -411,9 +457,10 @@ export class AssistsX {
|
|
|
411
457
|
* @param className 类名
|
|
412
458
|
* @returns 父节点
|
|
413
459
|
*/
|
|
414
|
-
public static findFirstParentByTags(className: string): Node {
|
|
460
|
+
public static findFirstParentByTags(node: Node, className: string): Node {
|
|
415
461
|
const response = this.call(CallMethod.findFirstParentByTags, {
|
|
416
462
|
args: { className },
|
|
463
|
+
node,
|
|
417
464
|
});
|
|
418
465
|
return Node.create(response.getDataOrDefault("{}"));
|
|
419
466
|
}
|
|
@@ -773,41 +820,25 @@ export class AssistsX {
|
|
|
773
820
|
/**
|
|
774
821
|
* 添加无障碍事件监听器
|
|
775
822
|
* @param listener 监听器函数
|
|
776
|
-
* @returns 监听器ID,用于移除监听器
|
|
777
823
|
*/
|
|
778
824
|
public static addAccessibilityEventListener(
|
|
779
|
-
listener:
|
|
780
|
-
):
|
|
781
|
-
|
|
782
|
-
const wrappedListener = (event: any) => {
|
|
783
|
-
try {
|
|
784
|
-
listener(event);
|
|
785
|
-
} catch (error) {
|
|
786
|
-
console.error("Accessibility event listener error:", error);
|
|
787
|
-
}
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
// 将监听器包装并存储,使用ID作为键
|
|
791
|
-
(accessibilityEventListeners as any)[listenerId] = wrappedListener;
|
|
792
|
-
accessibilityEventListeners.push(wrappedListener);
|
|
793
|
-
|
|
794
|
-
return listenerId;
|
|
825
|
+
listener: AccessibilityEventListener
|
|
826
|
+
): void {
|
|
827
|
+
accessibilityEventListeners.push(listener);
|
|
795
828
|
}
|
|
796
829
|
|
|
797
830
|
/**
|
|
798
831
|
* 移除无障碍事件监听器
|
|
799
|
-
* @param
|
|
832
|
+
* @param listener 要移除的监听器函数
|
|
800
833
|
* @returns 是否移除成功
|
|
801
834
|
*/
|
|
802
|
-
public static removeAccessibilityEventListener(
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
return true;
|
|
810
|
-
}
|
|
835
|
+
public static removeAccessibilityEventListener(
|
|
836
|
+
listener: AccessibilityEventListener
|
|
837
|
+
): boolean {
|
|
838
|
+
const index = accessibilityEventListeners.indexOf(listener);
|
|
839
|
+
if (index > -1) {
|
|
840
|
+
accessibilityEventListeners.splice(index, 1);
|
|
841
|
+
return true;
|
|
811
842
|
}
|
|
812
843
|
return false;
|
|
813
844
|
}
|
package/src/AssistsXAsync.ts
CHANGED
|
@@ -29,12 +29,14 @@ export class AssistsXAsync {
|
|
|
29
29
|
callbackId: uuid,
|
|
30
30
|
};
|
|
31
31
|
const promise = new Promise((resolve) => {
|
|
32
|
-
callbacks
|
|
32
|
+
callbacks.set(uuid, (data: string) => {
|
|
33
33
|
resolve(data);
|
|
34
|
-
};
|
|
34
|
+
});
|
|
35
35
|
setTimeout(() => {
|
|
36
|
+
// 超时后删除回调函数
|
|
37
|
+
callbacks.delete(uuid);
|
|
36
38
|
resolve(new CallResponse(0, null, uuid));
|
|
37
|
-
},
|
|
39
|
+
}, 1000 * 30);
|
|
38
40
|
});
|
|
39
41
|
const result = window.assistsxAsync.call(JSON.stringify(params));
|
|
40
42
|
const promiseResult = await promise;
|
|
@@ -347,9 +349,13 @@ export class AssistsXAsync {
|
|
|
347
349
|
* @param className 类名
|
|
348
350
|
* @returns 父节点
|
|
349
351
|
*/
|
|
350
|
-
public static async findFirstParentByTags(
|
|
352
|
+
public static async findFirstParentByTags(
|
|
353
|
+
node: Node,
|
|
354
|
+
className: string
|
|
355
|
+
): Promise<Node> {
|
|
351
356
|
const response = await this.asyncCall(CallMethod.findFirstParentByTags, {
|
|
352
357
|
args: { className },
|
|
358
|
+
node,
|
|
353
359
|
});
|
|
354
360
|
return Node.create(response.getDataOrDefault("{}"));
|
|
355
361
|
}
|
package/src/Node.ts
CHANGED
|
@@ -84,6 +84,18 @@ export class Node {
|
|
|
84
84
|
return new NodeAsync(this);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* 查找第一个匹配标签的父节点
|
|
89
|
+
* @param className 类名
|
|
90
|
+
* @returns 父节点
|
|
91
|
+
*/
|
|
92
|
+
public findFirstParentByTags(className: string): Node {
|
|
93
|
+
Step.assert(this.stepId);
|
|
94
|
+
const node = AssistsX.findFirstParentByTags(this, className);
|
|
95
|
+
Step.assert(this.stepId);
|
|
96
|
+
return node;
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
/**
|
|
88
100
|
* 对节点执行点击手势
|
|
89
101
|
* @param offsetX X轴偏移
|
package/src/NodeAsync.ts
CHANGED
|
@@ -18,7 +18,20 @@ export class NodeAsync {
|
|
|
18
18
|
constructor(node: Node) {
|
|
19
19
|
this.node = node;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* 查找第一个匹配标签的父节点
|
|
23
|
+
* @param className 类名
|
|
24
|
+
* @returns 父节点
|
|
25
|
+
*/
|
|
26
|
+
public async findFirstParentByTags(className: string): Promise<Node> {
|
|
27
|
+
Step.assert(this.node.stepId);
|
|
28
|
+
const node = await AssistsXAsync.findFirstParentByTags(
|
|
29
|
+
this.node,
|
|
30
|
+
className
|
|
31
|
+
);
|
|
32
|
+
Step.assert(this.node.stepId);
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
22
35
|
/**
|
|
23
36
|
* 对节点执行点击手势
|
|
24
37
|
* @param offsetX X轴偏移
|
package/src/Step.ts
CHANGED
|
@@ -10,6 +10,15 @@ import { generateUUID } from "./Utils";
|
|
|
10
10
|
import { StepError } from "./StepError";
|
|
11
11
|
import { StepAsync } from "./StepAsync";
|
|
12
12
|
|
|
13
|
+
// 步骤结果类型,可以是Step实例或undefined
|
|
14
|
+
export type StepResult = Step | undefined;
|
|
15
|
+
|
|
16
|
+
// 步骤实现函数类型
|
|
17
|
+
export type StepImpl = (step: Step) => Promise<StepResult>;
|
|
18
|
+
|
|
19
|
+
// 步骤拦截器函数类型
|
|
20
|
+
export type StepInterceptor = (step: Step) => StepResult | Promise<StepResult>;
|
|
21
|
+
|
|
13
22
|
export class Step {
|
|
14
23
|
static delayMsDefault: number = 1000;
|
|
15
24
|
static readonly repeatCountInfinite: number = -1;
|
|
@@ -21,6 +30,11 @@ export class Step {
|
|
|
21
30
|
*/
|
|
22
31
|
private static _stepId: string | undefined = undefined;
|
|
23
32
|
|
|
33
|
+
/**
|
|
34
|
+
* 步骤拦截器列表
|
|
35
|
+
*/
|
|
36
|
+
private static _interceptors: StepInterceptor[] = [];
|
|
37
|
+
|
|
24
38
|
/**
|
|
25
39
|
* 运行步骤实现
|
|
26
40
|
* @param impl 步骤实现函数
|
|
@@ -29,18 +43,14 @@ export class Step {
|
|
|
29
43
|
* @param delayMs 步骤延迟时间(毫秒)
|
|
30
44
|
*/
|
|
31
45
|
static async run(
|
|
32
|
-
impl:
|
|
46
|
+
impl: StepImpl,
|
|
33
47
|
{
|
|
34
48
|
tag,
|
|
35
49
|
data,
|
|
36
|
-
backupSteps,
|
|
37
50
|
delayMs = Step.delayMsDefault,
|
|
38
51
|
}: {
|
|
39
52
|
tag?: string | undefined;
|
|
40
53
|
data?: any | undefined;
|
|
41
|
-
backupSteps?:
|
|
42
|
-
| { [key: string]: (step: Step) => Promise<Step | undefined> }
|
|
43
|
-
| undefined;
|
|
44
54
|
delayMs?: number;
|
|
45
55
|
} = {}
|
|
46
56
|
): Promise<Step> {
|
|
@@ -58,7 +68,6 @@ export class Step {
|
|
|
58
68
|
impl,
|
|
59
69
|
tag,
|
|
60
70
|
data,
|
|
61
|
-
backupSteps,
|
|
62
71
|
delayMs,
|
|
63
72
|
});
|
|
64
73
|
while (true) {
|
|
@@ -76,7 +85,54 @@ export class Step {
|
|
|
76
85
|
`执行步骤${implnName},重复次数${currentStep.repeatCount}`
|
|
77
86
|
);
|
|
78
87
|
}
|
|
79
|
-
|
|
88
|
+
|
|
89
|
+
// 执行拦截器
|
|
90
|
+
let interceptedStep: StepResult = undefined;
|
|
91
|
+
for (const interceptor of this._interceptors) {
|
|
92
|
+
try {
|
|
93
|
+
const result = await interceptor(currentStep);
|
|
94
|
+
if (result !== undefined) {
|
|
95
|
+
interceptedStep = result;
|
|
96
|
+
if (Step.showLog) {
|
|
97
|
+
console.log(`步骤${implnName}被拦截器拦截,执行拦截后的步骤`);
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
} catch (e: any) {
|
|
102
|
+
if (Step.showLog) {
|
|
103
|
+
console.error(`拦截器执行出错`, e);
|
|
104
|
+
}
|
|
105
|
+
// 拦截器出错不影响主流程,继续执行原步骤
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 如果被拦截,执行拦截后的步骤,否则执行原步骤
|
|
110
|
+
if (interceptedStep !== undefined) {
|
|
111
|
+
// 执行拦截后的步骤,需要处理延迟和重复次数
|
|
112
|
+
const stepToExecute = interceptedStep;
|
|
113
|
+
|
|
114
|
+
// 如果拦截后的步骤有延迟时间,先执行延迟
|
|
115
|
+
if (stepToExecute.delayMs) {
|
|
116
|
+
if (Step.showLog) {
|
|
117
|
+
console.log(`拦截步骤延迟${stepToExecute.delayMs}毫秒`);
|
|
118
|
+
}
|
|
119
|
+
await stepToExecute.delay(stepToExecute.delayMs);
|
|
120
|
+
Step.assert(stepToExecute.stepId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 打印拦截步骤的执行信息
|
|
124
|
+
const interceptedImplName = stepToExecute.impl.name;
|
|
125
|
+
if (Step.showLog) {
|
|
126
|
+
console.log(
|
|
127
|
+
`执行拦截步骤${interceptedImplName},重复次数${stepToExecute.repeatCount}`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 执行拦截后的步骤
|
|
132
|
+
nextStep = await stepToExecute.impl(stepToExecute);
|
|
133
|
+
} else {
|
|
134
|
+
nextStep = await currentStep.impl(currentStep);
|
|
135
|
+
}
|
|
80
136
|
if (
|
|
81
137
|
currentStep.repeatCountMax > Step.repeatCountInfinite &&
|
|
82
138
|
currentStep.repeatCount > currentStep.repeatCountMax
|
|
@@ -159,6 +215,40 @@ export class Step {
|
|
|
159
215
|
this._stepId = undefined;
|
|
160
216
|
}
|
|
161
217
|
|
|
218
|
+
/**
|
|
219
|
+
* 添加步骤拦截器
|
|
220
|
+
* @param interceptor 拦截器函数
|
|
221
|
+
*/
|
|
222
|
+
static addInterceptor(interceptor: StepInterceptor): void {
|
|
223
|
+
this._interceptors.push(interceptor);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 移除步骤拦截器
|
|
228
|
+
* @param interceptor 要移除的拦截器函数
|
|
229
|
+
*/
|
|
230
|
+
static removeInterceptor(interceptor: StepInterceptor): void {
|
|
231
|
+
const index = this._interceptors.indexOf(interceptor);
|
|
232
|
+
if (index > -1) {
|
|
233
|
+
this._interceptors.splice(index, 1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 清空所有拦截器
|
|
239
|
+
*/
|
|
240
|
+
static clearInterceptors(): void {
|
|
241
|
+
this._interceptors = [];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 获取所有拦截器
|
|
246
|
+
* @returns 拦截器数组
|
|
247
|
+
*/
|
|
248
|
+
static getInterceptors(): StepInterceptor[] {
|
|
249
|
+
return [...this._interceptors];
|
|
250
|
+
}
|
|
251
|
+
|
|
162
252
|
/**
|
|
163
253
|
* 步骤ID
|
|
164
254
|
*/
|
|
@@ -192,14 +282,7 @@ export class Step {
|
|
|
192
282
|
/**
|
|
193
283
|
* 步骤实现函数
|
|
194
284
|
*/
|
|
195
|
-
impl:
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 备份步骤,可用于在指定的步骤中转向其他步骤
|
|
199
|
-
*/
|
|
200
|
-
backupSteps:
|
|
201
|
-
| { [key: string]: (step: Step) => Promise<Step | undefined> }
|
|
202
|
-
| undefined;
|
|
285
|
+
impl: StepImpl;
|
|
203
286
|
|
|
204
287
|
/**
|
|
205
288
|
* 构造函数
|
|
@@ -214,17 +297,13 @@ export class Step {
|
|
|
214
297
|
impl,
|
|
215
298
|
tag,
|
|
216
299
|
data,
|
|
217
|
-
backupSteps,
|
|
218
300
|
delayMs = Step.delayMsDefault,
|
|
219
301
|
repeatCountMax = Step.repeatCountMaxDefault,
|
|
220
302
|
}: {
|
|
221
303
|
stepId: string;
|
|
222
|
-
impl:
|
|
304
|
+
impl: StepImpl;
|
|
223
305
|
tag?: string | undefined;
|
|
224
306
|
data?: any | undefined;
|
|
225
|
-
backupSteps?:
|
|
226
|
-
| { [key: string]: (step: Step) => Promise<Step | undefined> }
|
|
227
|
-
| undefined;
|
|
228
307
|
delayMs?: number;
|
|
229
308
|
repeatCountMax?: number;
|
|
230
309
|
}) {
|
|
@@ -232,7 +311,6 @@ export class Step {
|
|
|
232
311
|
this.stepId = stepId;
|
|
233
312
|
this.data = data;
|
|
234
313
|
this.impl = impl;
|
|
235
|
-
this.backupSteps = backupSteps;
|
|
236
314
|
this.delayMs = delayMs;
|
|
237
315
|
this.repeatCountMax = repeatCountMax;
|
|
238
316
|
}
|
|
@@ -249,19 +327,15 @@ export class Step {
|
|
|
249
327
|
* @returns 新的步骤实例
|
|
250
328
|
*/
|
|
251
329
|
next(
|
|
252
|
-
impl:
|
|
330
|
+
impl: StepImpl,
|
|
253
331
|
{
|
|
254
332
|
tag,
|
|
255
333
|
data,
|
|
256
|
-
backupSteps,
|
|
257
334
|
delayMs = Step.delayMsDefault,
|
|
258
335
|
repeatCountMax = Step.repeatCountMaxDefault,
|
|
259
336
|
}: {
|
|
260
337
|
tag?: string | undefined;
|
|
261
338
|
data?: any | undefined;
|
|
262
|
-
backupSteps?:
|
|
263
|
-
| { [key: string]: (step: Step) => Promise<Step | undefined> }
|
|
264
|
-
| undefined;
|
|
265
339
|
delayMs?: number;
|
|
266
340
|
repeatCountMax?: number;
|
|
267
341
|
} = {}
|
|
@@ -272,7 +346,6 @@ export class Step {
|
|
|
272
346
|
impl,
|
|
273
347
|
tag,
|
|
274
348
|
data: data ?? this.data,
|
|
275
|
-
backupSteps: backupSteps ?? this.backupSteps,
|
|
276
349
|
delayMs,
|
|
277
350
|
repeatCountMax,
|
|
278
351
|
});
|
|
@@ -290,16 +363,12 @@ export class Step {
|
|
|
290
363
|
stepId = this.stepId,
|
|
291
364
|
tag = this.tag,
|
|
292
365
|
data = this.data,
|
|
293
|
-
backupSteps = this.backupSteps,
|
|
294
366
|
delayMs = this.delayMs,
|
|
295
367
|
repeatCountMax = this.repeatCountMax,
|
|
296
368
|
}: {
|
|
297
369
|
stepId?: string;
|
|
298
370
|
tag?: string | undefined;
|
|
299
371
|
data?: any | undefined;
|
|
300
|
-
backupSteps?:
|
|
301
|
-
| { [key: string]: (step: Step) => Promise<Step | undefined> }
|
|
302
|
-
| undefined;
|
|
303
372
|
delayMs?: number;
|
|
304
373
|
repeatCountMax?: number;
|
|
305
374
|
} = {}): Step {
|
|
@@ -308,7 +377,6 @@ export class Step {
|
|
|
308
377
|
this.stepId = stepId;
|
|
309
378
|
this.tag = tag;
|
|
310
379
|
this.data = data;
|
|
311
|
-
this.backupSteps = backupSteps;
|
|
312
380
|
this.delayMs = delayMs;
|
|
313
381
|
this.repeatCountMax = repeatCountMax;
|
|
314
382
|
return this;
|
|
@@ -550,18 +618,6 @@ export class Step {
|
|
|
550
618
|
return texts;
|
|
551
619
|
}
|
|
552
620
|
|
|
553
|
-
/**
|
|
554
|
-
* 查找第一个匹配标签的父节点
|
|
555
|
-
* @param className 类名
|
|
556
|
-
* @returns 父节点
|
|
557
|
-
*/
|
|
558
|
-
public findFirstParentByTags(className: string): Node {
|
|
559
|
-
Step.assert(this.stepId);
|
|
560
|
-
const node = AssistsX.findFirstParentByTags(className);
|
|
561
|
-
Step.assert(this.stepId);
|
|
562
|
-
return node;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
621
|
/**
|
|
566
622
|
* 执行点击手势
|
|
567
623
|
* @param x 横坐标
|
package/src/StepAsync.ts
CHANGED
|
@@ -231,18 +231,6 @@ export class StepAsync {
|
|
|
231
231
|
return texts;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
/**
|
|
235
|
-
* 查找第一个匹配标签的父节点
|
|
236
|
-
* @param className 类名
|
|
237
|
-
* @returns 父节点
|
|
238
|
-
*/
|
|
239
|
-
public async findFirstParentByTags(className: string): Promise<Node> {
|
|
240
|
-
Step.assert(this.step.stepId);
|
|
241
|
-
const node = await AssistsXAsync.findFirstParentByTags(className);
|
|
242
|
-
Step.assert(this.step.stepId);
|
|
243
|
-
return node;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
234
|
/**
|
|
247
235
|
* 执行点击手势
|
|
248
236
|
* @param x 横坐标
|
package/src/Utils.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
// 导出工具函数
|
|
2
2
|
export function sleep(ms: number): Promise<void> {
|
|
3
|
-
|
|
3
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// 生成UUID
|
|
7
7
|
export function generateUUID(): string {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
8
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
9
|
+
const r = (Math.random() * 16) | 0;
|
|
10
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
11
|
+
return v.toString(16);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function decodeBase64UTF8(base64: string): string {
|
|
16
|
+
const binary = atob(base64);
|
|
17
|
+
const bytes = new Uint8Array(binary.length);
|
|
18
|
+
for (let i = 0; i < binary.length; i++) {
|
|
19
|
+
bytes[i] = binary.charCodeAt(i);
|
|
20
|
+
}
|
|
21
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
22
|
+
}
|