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.
@@ -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
- [key: string]: (data: any) => void;
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: (event: any) => void): string;
380
+ static addAccessibilityEventListener(listener: AccessibilityEventListener): void;
360
381
  /**
361
382
  * 移除无障碍事件监听器
362
- * @param listenerId 监听器ID
383
+ * @param listener 要移除的监听器函数
363
384
  * @returns 是否移除成功
364
385
  */
365
- static removeAccessibilityEventListener(listenerId: string): boolean;
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
- const response = JSON.parse(data);
18
- const callback = callbacks[response.callbackId];
19
- if (callback) {
20
- callback(data);
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
- listener(event);
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[uuid] = (data) => {
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
- }, 10000);
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
- const listenerId = generateUUID();
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 listenerId 监听器ID
594
+ * @param listener 要移除的监听器函数
586
595
  * @returns 是否移除成功
587
596
  */
588
- static removeAccessibilityEventListener(listenerId) {
589
- const listener = accessibilityEventListeners[listenerId];
590
- if (listener) {
591
- const index = accessibilityEventListeners.indexOf(listener);
592
- if (index > -1) {
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
  }
@@ -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 父节点
@@ -25,12 +25,14 @@ export class AssistsXAsync {
25
25
  callbackId: uuid,
26
26
  };
27
27
  const promise = new Promise((resolve) => {
28
- callbacks[uuid] = (data) => {
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
- }, 10000);
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轴偏移
@@ -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: (step: Step) => Promise<Step | undefined>, { tag, data, backupSteps, delayMs, }?: {
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: (step: Step) => Promise<Step | undefined>;
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, backupSteps, delayMs, repeatCountMax, }: {
105
+ constructor({ stepId, impl, tag, data, delayMs, repeatCountMax, }: {
89
106
  stepId: string;
90
- impl: (step: Step) => Promise<Step | undefined>;
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: (step: Step) => Promise<Step | undefined>, { tag, data, backupSteps, delayMs, repeatCountMax, }?: {
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, backupSteps, delayMs, repeatCountMax, }?: {
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, backupSteps, delayMs = Step.delayMsDefault, } = {}) {
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
- nextStep = await currentStep.impl(currentStep);
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, backupSteps, delayMs = Step.delayMsDefault, repeatCountMax = Step.repeatCountMaxDefault, }) {
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, backupSteps, delayMs = Step.delayMsDefault, repeatCountMax = Step.repeatCountMaxDefault, } = {}) {
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, backupSteps = this.backupSteps, delayMs = this.delayMs, repeatCountMax = this.repeatCountMax, } = {}) {
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 = [];
@@ -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
@@ -1,2 +1,3 @@
1
1
  export declare function sleep(ms: number): Promise<void>;
2
2
  export declare function generateUUID(): string;
3
+ export declare function decodeBase64UTF8(base64: string): string;
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 '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);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistsx-js",
3
- "version": "0.0.2001",
3
+ "version": "0.0.2003",
4
4
  "description": "assistsx-js自动化开发SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
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: { [key: string]: (data: any) => void } = {};
52
+ export const callbacks: Map<string, (data: string) => void> = new Map();
26
53
 
27
54
  // 无障碍事件监听器存储
28
- export const accessibilityEventListeners: ((event: any) => void)[] = [];
55
+ export const accessibilityEventListeners: AccessibilityEventListener[] = [];
29
56
 
30
57
  // 初始化全局回调函数
31
58
  if (typeof window !== "undefined" && !window.assistsxCallback) {
32
59
  window.assistsxCallback = (data: string) => {
33
- const response = JSON.parse(data);
34
- const callback = callbacks[response.callbackId];
35
- if (callback) {
36
- callback(data);
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: any) => {
44
- // 通知所有注册的监听器
84
+ window.onAccessibilityEvent = (event: string) => {
85
+ // 通知所有注册的监听器,每个监听器都有独立的错误处理
45
86
  accessibilityEventListeners.forEach((listener) => {
46
87
  try {
47
- listener(event);
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[uuid] = (data: any) => {
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
- }, 10000);
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: (event: any) => void
780
- ): string {
781
- const listenerId = generateUUID();
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 listenerId 监听器ID
832
+ * @param listener 要移除的监听器函数
800
833
  * @returns 是否移除成功
801
834
  */
802
- public static removeAccessibilityEventListener(listenerId: string): boolean {
803
- const listener = (accessibilityEventListeners as any)[listenerId];
804
- if (listener) {
805
- const index = accessibilityEventListeners.indexOf(listener);
806
- if (index > -1) {
807
- accessibilityEventListeners.splice(index, 1);
808
- delete (accessibilityEventListeners as any)[listenerId];
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
  }
@@ -29,12 +29,14 @@ export class AssistsXAsync {
29
29
  callbackId: uuid,
30
30
  };
31
31
  const promise = new Promise((resolve) => {
32
- callbacks[uuid] = (data: any) => {
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
- }, 10000);
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(className: string): Promise<Node> {
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: (step: Step) => Promise<Step | undefined>,
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
- nextStep = await currentStep.impl(currentStep);
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: (step: Step) => Promise<Step | undefined>;
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: (step: Step) => Promise<Step | undefined>;
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: (step: Step) => Promise<Step | undefined>,
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
- return new Promise(resolve => setTimeout(resolve, ms));
3
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
4
  }
5
5
 
6
6
  // 生成UUID
7
7
  export function generateUUID(): string {
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
- }
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
+ }