脚本引擎 API

AI 脚本高级模式

覆盖编辑器超出简单线性顺序执行的高级能力:运行时条件守卫、错误处理、事件驱动、子流程、变量循环、并行竞速、标签跳转、复合条件与防检测模式。用于生成真正的复杂生产级脚本。

当前:AI 脚本高级模式
脚本引擎 API

AI 脚本高级模式

覆盖编辑器超出简单线性顺序执行的高级能力:运行时条件守卫、错误处理、事件驱动、子流程、变量循环、并行竞速、标签跳转、复合条件与防检测模式。用于生成真正的复杂生产级脚本。

概述

本页定义编辑器中超出「顺序执行」的高级脚本模式。

基础规范可以让 AI 生成线性脚本(tap → delay → tap),但实际生产脚本需要条件守卫、错误处理、变量循环、事件驱动和模块化设计。

本页按使用场景分类给出 JSON 示例,AI 应根据需求组合使用。AI 应优先输出原生节点结构,并确保每个节点的 id 唯一。

模式一:动作运行时条件守卫

每个动作节点可通过 ActionConfig 附加运行时条件。动作执行前先判断条件,条件不满足时跳过或失败。

{"type": "action", "action": {"type": "tap", "x": 540, "y": 1100}, "config": {"runtimeConditions": {"type": "and", "conditions": [{"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "确认"}]}, "conditionMissStrategy": "SKIP"}}

  • runtimeConditions 使用 ConditionGroup,支持 AND/OR/NOT 组合任意条件(视觉、时间、变量)。
  • conditionMissStrategy = SKIP(跳过当前动作继续执行)/ FAIL(动作失败)。
  • conditionNegated = true 时条件取反(不满足才执行)。
  • checkConditionsBeforePreDelay = true(默认)时在 preDelay 前检查条件。

模式二:失败重试与错误处理

动作执行失败时可自动重试,也可用 TryCatch 节点做兜底分支。

重试配置在 ActionConfig 中:

{"type": "action", "action": {...}, "config": {"retryTimes": 5, "retryIntervalMs": 500}}

TryCatch 兜底:

{"type": "try_catch", "tryBlock": {"nodes": [{"type": "action", "action": {"type": "find_and_click", "text": "确认"}}]}, "catchBlock": {"nodes": [{"type": "action", "action": {"type": "tap", "x": 540, "y": 1000}}]}}

  • retryTimes = -1 表示无限重试直到成功。retryTimes = 0(默认)不重试。
  • retryIntervalMs 控制重试间隔。
  • TryCatch 是结构节点:tryBlock 执行失败时自动进入 catchBlock。
  • tryBlock 内任何节点失败都会触发 catch 逻辑,适合用于关键路径保护。

模式三:变量设置与循环模式

使用变量追踪状态,配合 WhileVar 实现循环控制。

示例 - 带计数器的重试循环:

{"type": "set_var", "key": "retry_count", "value": 0}

{"type": "label", "name": "retry_loop"}

{"type": "action", "comment": "点击尝试", "action": {"type": "find_and_click", "text": "领取"}}

{"type": "action", "comment": "等待结果", "action": {"type": "wait_for_vision", "condition": {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "领取成功"}, "timeoutMillis": 5000}}

{"type": "inc_var", "key": "retry_count", "delta": 1}

{"type": "while_var", "key": "retry_count", "op": "LT", "value": 5, "maxIterations": 20, "block": {"nodes": [{"type": "goto", "target": "retry_loop"}]}}

  • IncVar 递增变量值,delta 可正可负。
  • WhileVar 在变量条件满足时循环执行 block 内的节点。
  • maxIterations 建议设置,防止无限循环。
  • CompareOp 枚举值:LT(<)、LE(<=)、EQ(==)、NE(!=)、GE(>=)、GT(>)。
  • 也可用 WhileVision 做视觉条件循环:while_vision 在视觉条件满足时循环。

模式四:视觉条件循环

视觉条件循环:每次循环检查视觉条件,满足则执行 block 内节点。适合持续刷取直到目标出现/消失。

{"type": "while_vision", "condition": {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "加载中"}, "block": {"nodes": [{"type": "action", "action": {"type": "delay", "millis": 1000}}]}}

模式五:变量分支(VarSwitch)

根据变量值跳转到不同分支执行。类似 switch-case 语句。

{"type": "var_switch", "key": "status", "matchMode": "TEXT_EQUALS", "cases": [{"matchValue": "success", "block": {"nodes": [{"type": "action", "action": {"type": "delay", "millis": 500}}]}}, {"matchValue": "fail", "block": {"nodes": [{"type": "action", "action": {"type": "find_and_click", "text": "重试"}}]}}], "defaultBlock": {"nodes": [{"type": "action", "action": {"type": "tap", "x": 540, "y": 1000}}]}}

  • matchMode 可选:TEXT_EQUALS(文本精确匹配)、CONTAINS(包含)、STARTS_WITH、ENDS_WITH、REGEX。
  • cases 是分支列表,按顺序匹配第一个命中的分支。
  • defaultBlock 是所有分支都不匹配时执行的默认逻辑。

模式六:子流程模块化

将可复用的逻辑定义为子流程(SubFlowDef),通过 CallSubFlow 调用。

定义子流程:

{"type": "subflow_def", "name": "登录流程", "params": [{"name": "username", "defaultValue": ""}, {"name": "password", "defaultValue": ""}], "block": {"nodes": [{"type": "action", "action": {"type": "node_input", "selector": {"className": "EditText", "instanceIndex": 0}, "inputText": ""}}, {"type": "action", "action": {"type": "node_input", "selector": {"className": "EditText", "instanceIndex": 1}, "inputText": ""}}, {"type": "action", "action": {"type": "find_and_click", "text": "登录"}}]}}

调用子流程:

{"type": "call_subflow", "targetName": "登录流程", "paramBindings": [{"paramName": "username", "value": "user123"}, {"paramName": "password", "value": "pass456"}]}

  • 子流程定义只能在脚本顶层 root 中定义,不能在 if/thenBlock 等嵌套中定义。
  • paramBindings 用于传入参数值。
  • 同一子流程可被多次调用,适合重复性操作(如登录、签到、领取)。

模式七:事件驱动

通过 EventListener 监听动作运行时的事件,触发对应的子流程。

定义事件监听:

{"type": "event_listener", "eventName": "on_task_complete", "targetSubFlow": "领取奖励"}

使用场景:某个动作完成后触发子流程,例如点击后等待对话框弹出再领取奖励。

  • 事件名可用自定义名称,在动作执行器中通过 runtime 触发。
  • targetSubFlow 指向已定义的 subflow_def 名称。
  • 适合解耦:主流程与后处理逻辑分离。

模式八:并行竞速(Race)

左右两个分支同时执行,先完成的一路生效,另一路自动取消。

{"type": "race", "leftBlock": {"nodes": [{"type": "action", "action": {"type": "wait_for_vision", "condition": {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "成功"}, "timeoutMillis": 10000}}]}, "rightBlock": {"nodes": [{"type": "action", "action": {"type": "wait_for_vision", "condition": {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "失败"}, "timeoutMillis": 10000}}]}}

  • race 适合「竞速等待」场景,比如同时等待成功和失败对话框,哪个先出现就执行哪个。
  • 未生效的分支会被自动取消。

模式九:标签跳转流程控制

通过 Label 和 Goto 实现跨层跳转,不受嵌套层级限制。

{"type": "label", "name": "exit_point"} // 定义跳转目标

{"type": "goto", "target": "exit_point"} // 跳转到目标标签

Goto 可以从 if 的 thenBlock、repeat 的 block 等深层嵌套中直接跳出。

  • label 和 goto 的 name/target 必须匹配。
  • goto 可向上冒泡(跳出循环/条件)但不可向下跳入(goto 目标必须在当前位置之后或同一层级)。
  • break 和 continue 分别用于跳出当前循环和跳到下次循环。

模式十:复合条件组合(ConditionGroup)

将多个条件通过 AND/OR/NOT 组合为复合条件,可用于 if 节点和运行时条件守卫。

AND 组合(所有条件满足才通过):

{"type": "if", "conditions": {"type": "and", "conditions": [{"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "确认"}, {"type": "time", "timeCondition": {"startTime": "08:00", "endTime": "22:00"}}]}, "thenBlock": {"nodes": []}}

OR 组合(任一条件满足即通过):

{"type": "if", "conditions": {"type": "or", "conditions": [{"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "成功"}, {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "完成"}]}, "thenBlock": {"nodes": []}}

NOT 组合(取反):

{"type": "if", "conditions": {"type": "not", "conditions": [{"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "加载中"}]}, "thenBlock": {"nodes": []}}

模式十一:坐标偏移与防检测

通过 ActionConfig 的坐标随机偏移,使每次点击位置略有不同,降低被检测为自动化操作的风险。

{"type": "action", "action": {"type": "tap", "x": 540, "y": 1100}, "config": {"coordJitterMinPx": -3, "coordJitterMaxPx": 3, "preDelayMs": 800, "postDelayMs": 1200}}

  • coordJitterMinPx/coordJitterMaxPx:点击位置在 [-3, 3] 像素范围内随机偏移。
  • preDelayMs:动作前随机等待(0~800ms)。postDelayMs:动作后固定等待(1200ms)。
  • preDelayRandomRangeMs:也可以设置 preDelay 的随机范围。
  • 随机延迟 + 随机偏移的组合可以有效减少被检测特征。

综合示例:带重试的登录流程

以下是一个使用变量循环 + 子流程 + 条件守卫 + 标签跳转的完整脚本示例:

{ "id": "advanced-login-demo", "name": "高级登录示例", "root": { "nodes": [ {"type": "set_var", "key": "retry", "value": 0}, {"type": "label", "name": "login_attempt"}, {"type": "call_subflow", "targetName": "打开应用"}, {"type": "action", "action": {"type": "wait_for_vision", "condition": {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "登录"}, "timeoutMillis": 15000}}, {"type": "action", "action": {"type": "find_and_click", "text": "登录"}}, {"type": "action", "action": {"type": "node_input", "selector": {"className": "EditText", "instanceIndex": 0}, "inputText": "user123"}}, {"type": "action", "action": {"type": "node_input", "selector": {"className": "EditText", "instanceIndex": 1}, "inputText": "pass456"}}, {"type": "action", "action": {"type": "find_and_click", "text": "确认登录"}, "config": {"retryTimes": 3}}, {"type": "if", "conditions": {"type": "or", "conditions": [ {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "登录成功"}, {"type": "text_exists", "left": 0, "top": 0, "right": 1080, "bottom": 2400, "text": "首页"} ]}, "thenBlock": {"nodes": [ {"type": "goto", "target": "login_done"} ]}, "elseBlock": {"nodes": [ {"type": "inc_var", "key": "retry", "delta": 1}, {"type": "if", "conditions": {"type": "not", "conditions": [{"type": "var", "varCondition": {"key": "retry", "op": "LT", "value": 3}}]}, "thenBlock": {"nodes": [ {"type": "goto", "target": "login_failed"} ]}}, {"type": "goto", "target": "login_attempt"} ]}}, {"type": "label", "name": "login_done"}, {"type": "action", "comment": "登录完成", "action": {"type": "delay", "millis": 500}}, {"type": "label", "name": "login_failed"} ] } }

模式十二:变量表达式与运算

SetVar 节点的 value 字段除了直接赋值(数字、字符串、布尔值),还可以写入表达式字符串,由变量表达式引擎在运行时计算。

表达式格式:{ "kind": "expression", "expression": "a + b * 2", "resultType": "AUTO" }

在 SetVar 中使用表达式时,直接给 value 传入表达式对象:

{"type": "set_var", "key": "result", "value": {"kind": "expression", "expression": "a + b * 2", "resultType": "NUMBER"}}

  • resultType 可选:AUTO(自动推断)、NUMBER、BOOLEAN、TEXT、COORDINATE、ARRAY、NUMBER_ARRAY、BOOLEAN_ARRAY、TEXT_ARRAY、COORDINATE_ARRAY。

支持的运算符

二元运算符(优先级从高到低):

^ 幂运算,如 2 ^ 10 = 1024

* / % 乘除取模,如 a * 2

+ - 加减,如 retry_count + 1

== != < > <= >= 比较运算,返回布尔值

! 逻辑非(一元前缀)

&& 逻辑与,|| 逻辑或

支持的数学函数

基础数学:abs(x)、min(a,b,...)、max(a,b,...)、round(x)、floor(x)、ceil(x)、sqrt(x)、pow(x,y)

对数和指数:exp(x)、log(x)、log10(x)、hypot(x,y)

三角函数(弧度):sin(x)、cos(x)、tan(x)、asin(x)、acos(x)、atan(x)、atan2(y,x)

三角函数(角度):sinDeg(x)、cosDeg(x)、tanDeg(x)、asinDeg(x)、acosDeg(x)、atanDeg(x)、atan2Deg(y,x)

角度转换:radians(deg)、degrees(rad)

统计:sum(a,b,...)、avg(a,b,...)

支持的数组函数

数组由方括号创建:[1, 2, 3]、["a", "b"]

元素访问:arr[0]、arr[index]

count(arr) / len(arr):数组长度

first(arr)、last(arr)、at(arr, index)

slice(arr, start, end):截取子数组

contains(arr, value):是否包含

join(arr, sep):数组合并为字符串

split(str, sep):字符串拆分为数组

concat(arr1, arr2, ...):合并多个数组

reverse(arr):反转

unique(arr):去重

sort(arr):排序(数值升序)

sortByScore(arr, scoreFunc):按评分排序

随机与坐标

random():返回 [0, 1) 范围内的随机浮点数

randomInt(min, max):返回 [min, max] 范围内的随机整数

坐标值:(x, y) 表示一个坐标点,可赋值给支持 coordinate 类型的变量

表达式示例

表达式可引用脚本中其他 SetVar 定义的变量:

计算:retry_count + 1

混合运算:(a + b) * 2 / 3

条件判断:score >= 60

随机偏移:x + randomInt(-3, 3)

坐标运算:(x + offset, y + offset)

数组操作:sum(1, 2, 3, 4, 5)

字符串拼接:"用户" + name + "你好"

多参数统计:min(a, b, c, d)

模式十三:自定义 JS 脚本(run_code)

当现有节点无法满足复杂逻辑时,使用 run_code 节点执行自定义 JavaScript。节点内部通过 runtime.* 对象直接调用全部运行时能力。

run_code JSON 结构:

// 模式十三:自定义 JS 脚本综合示例
// 目标:检测页面状态 → 根据条件执行不同操作 → 写入结果变量

runtime.process.log("开始检测页面状态");

// 1. 等待关键元素出现
var pageReady = runtime.vision.waitForText("加载完成", 10000);
if (!pageReady) {
    runtime.process.error("页面加载超时");
    runtime.process.stop("页面未就绪");
}

runtime.process.log("页面已就绪,开始执行任务");

// 2. 读取配置文件
var configData = runtime.files.read("/sdcard/config.json");
runtime.variables.set("config", configData);
runtime.process.log("配置已加载: " + configData.length + " 字符");

// 3. 检测不同分支条件
var hasBonus = runtime.vision.textExists("领取奖励", 0, 0, 540, 200);
var hasError = runtime.vision.textExists("网络异常");

if (hasBonus) {
    // 分支 A:有奖励可领取
    runtime.process.log("发现奖励 → 领取");
    runtime.vision.clickText("领取奖励", 0, 0, 540, 200);
    if (runtime.vision.waitForText("领取成功", 5000)) {
        runtime.process.log("领取成功");
        runtime.variables.set("result", "success");
    } else {
        runtime.process.error("领取失败,截图保存");
        runtime.screen.capture("/sdcard/error_bonus.png");
        runtime.variables.set("result", "fail");
    }
} else if (hasError) {
    // 分支 B:网络异常 → 重试
    runtime.process.warn("网络异常 → 3 秒后重试");
    runtime.touch.sleep(3000);
    runtime.variables.set("need_retry", true);
} else {
    // 分支 C:正常态 → 继续下一个操作
    runtime.process.log("正常页面状态");
    runtime.touch.findAndClick("下一页");
}

// 4. 执行效果确认
runtime.screen.capture("/sdcard/result.png");
runtime.process.log("最终状态已截图保存");

// 5. 返回结果(写入 bindResultToVar)
"done";