Skip to content

Commit 340b4a2

Browse files
committed
feat(core): 新增浮窗权限设置接口并优化相关功能
- 在 ASJavascriptInterface 中添加 setOverlayFlags 方法,用于设置浮窗权限 - 在 AssistsWindowManager 中实现 setFlags 函数,用于更新浮窗参数 - 修改 AssistsCore 中的 paste 方法,优化剪贴板操作逻辑 - 更新 ASWebView 中的 WebView 设置,启用数据库和 DOM 存储功能 - 在 CallMethod 中添加 setOverlayFlags 常量,用于标识新功能
1 parent 5396020 commit 340b4a2

File tree

8 files changed

+430
-11
lines changed

8 files changed

+430
-11
lines changed

assists-web-simple/README-DEV.md

Lines changed: 389 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,389 @@
1+
# AssistsX
2+
3+
assistsx是一个基于AssistsX App脚本平台的TypeScript库,主要用于通过web方式实现Android平台的自动化脚本。
4+
assistsx提供了一系列用于与 Android App AssistsX交互的 TypeScript 类型和方法,支持节点查找、手势操作、界面自动化等能力。
5+
6+
## 安装
7+
8+
```bash
9+
npm install assistsx
10+
```
11+
12+
## 快速开始
13+
14+
### 基本用法
15+
16+
```typescript
17+
import { AssistsX, Node } from 'assistsx';
18+
19+
// 获取所有节点
20+
const nodes: Node[] = AssistsX.getAllNodes();
21+
22+
// 通过ID查找节点
23+
const nodeList: Node[] = AssistsX.findById('target_id');
24+
25+
// 点击第一个节点
26+
if (nodeList.length > 0) {
27+
AssistsX.click(nodeList[0]);
28+
}
29+
30+
// 执行手势点击
31+
AssistsX.gestureClick(100, 200, 50); // 在(100,200)位置点击,持续50ms
32+
```
33+
34+
### 节点对象的常用操作
35+
36+
```typescript
37+
const node: Node = nodeList[0];
38+
39+
// 设置节点文本
40+
node.setNodeText('new text');
41+
42+
// 节点点击
43+
node.click();
44+
45+
// 节点长按
46+
node.longClick();
47+
48+
// 节点滚动
49+
node.scrollForward();
50+
node.scrollBackward();
51+
52+
// 获取节点在屏幕中的位置
53+
const bounds = node.getBoundsInScreen();
54+
console.log(bounds);
55+
56+
// 节点截图
57+
const imagePath = await node.takeScreenshot();
58+
```
59+
60+
### 复杂查找与遍历
61+
62+
```typescript
63+
// 通过文本查找节点
64+
const textNodes = AssistsX.findByText('确定');
65+
66+
// 通过标签查找节点
67+
const tagNodes = AssistsX.findByTags('android.widget.Button', { filterText: '提交' });
68+
69+
// 获取节点的所有子节点
70+
const children = node.getChildren();
71+
```
72+
73+
## 主要类型说明
74+
75+
### AssistsX
76+
77+
- 提供静态方法用于节点查找、手势操作、系统操作等。
78+
- 常用方法:
79+
- `getAllNodes`:获取所有节点
80+
- `findById``findByText``findByTags`:多种查找方式
81+
- `click``longClick``gestureClick`:节点点击与手势
82+
- `takeScreenshotNodes`:节点截图
83+
- `launchApp``back``home``notifications``recentApps`:系统操作
84+
85+
### Node
86+
87+
- 表示界面上的一个可交互元素,包含属性和操作方法。
88+
- 主要属性:
89+
- `nodeId``text``des``viewId``className`
90+
- `isScrollable``isClickable``isEnabled`
91+
- 主要方法:
92+
- `setNodeText(text: string)`:设置文本
93+
- `click()``longClick()`:点击/长按
94+
- `scrollForward()``scrollBackward()`:滚动
95+
- `getBoundsInScreen()`:获取屏幕位置
96+
- `takeScreenshot()`:节点截图
97+
- `findById``findByText``findByTags`:在当前节点范围内查找
98+
99+
## 典型场景
100+
101+
### 1. 自动化测试
102+
103+
```typescript
104+
// 启动应用
105+
AssistsX.launchApp('com.example.app');
106+
107+
// 等待并点击登录按钮
108+
const loginBtn = AssistsX.findByText('登录');
109+
if (loginBtn.length > 0) {
110+
loginBtn[0].click();
111+
}
112+
113+
// 检查是否包含某文本
114+
const hasText = AssistsX.containsText('登录成功');
115+
```
116+
117+
### 2. 界面元素操作
118+
119+
```typescript
120+
// 查找输入框并输入文本
121+
const input = AssistsX.findById('input_field');
122+
if (input.length > 0) {
123+
input[0].setNodeText('测试文本');
124+
}
125+
126+
// 查找并点击提交按钮
127+
const submit = AssistsX.findByText('提交');
128+
if (submit.length > 0) {
129+
submit[0].click();
130+
}
131+
```
132+
133+
### 3. 手势操作
134+
135+
```typescript
136+
// 简单点击
137+
AssistsX.gestureClick(100, 200, 50);
138+
139+
// 节点手势点击(支持偏移)
140+
const node = AssistsX.findById('target')[0];
141+
await node.nodeGestureClick({
142+
offsetX: 10,
143+
offsetY: 10,
144+
clickDuration: 50
145+
});
146+
147+
// 双击操作
148+
await node.nodeGestureClickByDouble({
149+
clickInterval: 200
150+
});
151+
```
152+
153+
### 4. 滚动和导航
154+
155+
```typescript
156+
// 系统导航
157+
AssistsX.back(); // 返回
158+
AssistsX.home(); // 主页
159+
AssistsX.notifications(); // 通知栏
160+
161+
// 滚动操作
162+
const scrollable = AssistsX.findByTags('android.widget.ScrollView')[0];
163+
scrollable.scrollForward();
164+
scrollable.scrollBackward();
165+
```
166+
167+
## 注意事项
168+
169+
1. 使用前提
170+
- 确保 Android WebView 中已注入 `assistsx` 对象
171+
- 确保有足够的权限(如辅助功能权限)
172+
173+
2. 性能建议
174+
- 避免频繁查找节点,建议复用查找结果
175+
- 截图等耗时操作请合理使用
176+
177+
3. 异步操作
178+
- 截图、手势等操作为异步方法,需使用 `await`
179+
- 建议使用 try-catch 处理异常
180+
181+
4. 节点状态
182+
- 操作前建议检查节点的 `isEnabled``isClickable` 等状态
183+
- 使用 `isVisible` 确认节点是否可见
184+
185+
## API 文档
186+
187+
详细的 API 文档请参考源码中的 TypeScript 类型定义和注释说明。
188+
189+
## 问题反馈
190+
191+
如有问题或建议,欢迎提交 Issue 或 Pull Request。
192+
193+
## 步骤器(Step)使用说明
194+
195+
步骤器提供了一种结构化的方式来组织和执行自动化操作,支持步骤的生命周期管理、状态控制和界面操作。
196+
197+
### 基本用法
198+
199+
```typescript
200+
import { Step } from 'assistsx';
201+
202+
// 定义步骤实现
203+
async function loginStep(step: Step): Promise<Step | undefined> {
204+
// 启动应用
205+
step.launchApp('com.example.app');
206+
207+
// 查找用户名输入框并输入
208+
const usernameInput = step.findById('username_input');
209+
if (usernameInput.length > 0) {
210+
usernameInput[0].setNodeText('user123');
211+
}
212+
213+
// 查找密码输入框并输入
214+
const passwordInput = step.findById('password_input');
215+
if (passwordInput.length > 0) {
216+
passwordInput[0].setNodeText('password123');
217+
}
218+
219+
// 点击登录按钮
220+
const loginButton = step.findByText('登录');
221+
if (loginButton.length > 0) {
222+
loginButton[0].click();
223+
}
224+
225+
// 返回 undefined 表示步骤结束
226+
return undefined;
227+
}
228+
229+
// 运行步骤
230+
await Step.run(loginStep, {
231+
tag: 'login', // 步骤标签
232+
data: { user: 'test' }, // 步骤数据
233+
delayMs: 1000 // 步骤延迟
234+
});
235+
```
236+
237+
### 步骤链式调用
238+
239+
```typescript
240+
async function step1(step: Step): Promise<Step | undefined> {
241+
// 执行某些操作
242+
// ...
243+
244+
// 返回下一个步骤
245+
return step.next(step2, { tag: 'step2' });
246+
}
247+
248+
async function step2(step: Step): Promise<Step | undefined> {
249+
// 执行某些操作
250+
// ...
251+
252+
// 重复当前步骤
253+
if (needRepeat) {
254+
return step.repeat();
255+
}
256+
257+
// 返回下一个步骤
258+
return step.next(step3, { tag: 'step3' });
259+
}
260+
261+
async function step3(step: Step): Promise<Step | undefined> {
262+
// 执行最后的操作
263+
// ...
264+
265+
// 步骤结束
266+
return undefined;
267+
}
268+
269+
// 运行步骤链
270+
await Step.run(step1, { tag: 'step1' });
271+
```
272+
273+
### 异步操作处理
274+
275+
```typescript
276+
async function asyncStep(step: Step): Promise<Step | undefined> {
277+
// 等待异步操作
278+
await step.delay(1000);
279+
280+
// 执行异步方法
281+
const result = await step.await(async () => {
282+
// 异步操作
283+
return 'result';
284+
});
285+
286+
// 节点截图
287+
const node = step.findById('target')[0];
288+
const imagePath = await step.takeScreenshotByNode(node);
289+
290+
return undefined;
291+
}
292+
```
293+
294+
## Step API 文档
295+
296+
### 静态方法
297+
298+
#### `Step.run(impl, options)`
299+
运行步骤实现。
300+
- `impl`: `(step: Step) => Promise<Step | undefined>` - 步骤实现函数
301+
- `options`:
302+
- `tag?: string` - 步骤标签
303+
- `data?: any` - 步骤数据
304+
- `delayMs?: number` - 步骤延迟时间(毫秒),默认 1000
305+
306+
#### `Step.stop()`
307+
停止当前步骤执行。
308+
309+
### 实例属性
310+
311+
- `stepId: string` - 步骤ID
312+
- `repeatCount: number` - 步骤重复执行次数
313+
- `tag?: string` - 步骤标签
314+
- `data?: any` - 步骤数据
315+
- `delayMs: number` - 步骤延迟时间(毫秒)
316+
317+
### 实例方法
318+
319+
#### 步骤控制
320+
- `next(impl, options)` - 创建下一个步骤
321+
- `repeat(options)` - 重复当前步骤
322+
- `delay(ms)` - 延迟执行
323+
- `await<T>(method)` - 等待异步方法执行完成
324+
325+
#### 节点操作
326+
- `getAllNodes(options)` - 获取所有符合条件的节点
327+
- `findById(id, options)` - 通过ID查找节点
328+
- `findByText(text, options)` - 通过文本查找节点
329+
- `findByTags(className, options)` - 通过标签查找节点
330+
- `findByTextAllMatch(text)` - 查找所有匹配文本的节点
331+
- `findFirstParentByTags(className)` - 查找第一个匹配标签的父节点
332+
333+
#### 界面操作
334+
- `takeScreenshotByNode(node, delay)` - 对单个节点进行截图
335+
- `takeScreenshotNodes(nodes, delay)` - 对多个节点进行截图
336+
- `gestureClick(x, y, duration)` - 执行点击手势
337+
- `back()` - 返回操作
338+
- `home()` - 回到主页
339+
- `notifications()` - 打开通知栏
340+
- `recentApps()` - 显示最近应用
341+
342+
#### 应用控制
343+
- `launchApp(packageName)` - 启动应用
344+
- `getPackageName()` - 获取当前应用包名
345+
346+
#### 其他操作
347+
- `containsText(text)` - 检查是否包含指定文本
348+
- `getAllText()` - 获取所有文本
349+
- `getScreenSize()` - 获取屏幕尺寸
350+
- `getAppScreenSize()` - 获取应用窗口尺寸
351+
352+
## 最佳实践
353+
354+
1. 步骤组织
355+
- 将复杂的自动化流程拆分为多个步骤
356+
- 每个步骤专注于完成特定的任务
357+
- 使用有意义的标签和数据来标识步骤
358+
359+
2. 错误处理
360+
```typescript
361+
async function robustStep(step: Step): Promise<Step | undefined> {
362+
try {
363+
const node = step.findById('target')[0];
364+
if (!node) {
365+
throw new Error('Target node not found');
366+
}
367+
// ... 其他操作
368+
} catch (error) {
369+
console.error(`Step failed: ${error.message}`);
370+
// 可以选择重试或执行其他步骤
371+
return step.repeat({ delayMs: 2000 });
372+
}
373+
}
374+
```
375+
376+
3. 步骤复用
377+
```typescript
378+
// 创建可复用的步骤
379+
function createLoginStep(username: string, password: string) {
380+
return async function(step: Step): Promise<Step | undefined> {
381+
// ... 登录逻辑
382+
return undefined;
383+
}
384+
}
385+
386+
// 在不同地方复用
387+
await Step.run(createLoginStep('user1', 'pass1'));
388+
await Step.run(createLoginStep('user2', 'pass2'));
389+
```

0 commit comments

Comments
 (0)