Workflows:在安卓上自动化开发任务,无需服务器
用 PocketCode Workflows 在安卓上自动化任务:25 种触发器、分支与循环、cron、按工作流的权限和加密密钥——无需服务器,全程在设备本地运行。
每个开发者都会攒下同样一堆琐事:push 之后跑测试、部署落地后备份数据库、保存时格式化、 构建挂了要有人告诉你。在笔记本上,你用 CI runner、cron 任务和某台服务器上的几个 shell 脚本把这些串起来。在手机上,通常的答案是「做不到」。Pocket Code 用 Workflows 改变了这一点:一个事件驱动的自动化引擎,让你完全在设备上 自动化安卓上的任务,没有服务器要租,也没有东西要在云端保活。
一个工作流描述起来很简单:一个触发器(IDE 内的某个事件,或一个计划)加上一串在共享 上下文上运行的步骤。这就足以构建真正的开发流程——那种你通常会为它搭一条 CI 流水线的 流程——而且就在你的编辑器、终端和数据库管理器旁边。
四种创建方式
你永远不必从空白画布开始:
| 方式 | 怎么创建 | 例子 |
|---|---|---|
| 模板 | 在 17 个内置模板之一上点击 Activate | 「测试通过后部署」「检查一个接口」「部署后备份数据库」 |
| 讲给 AI 听 | 写一句话,得到可编辑的骨架 | 「每次 commit 之后跑测试,失败就通知我」会变成一个带失败分支的工作流 |
| 编辑器 | 用 "+" 按钮打开完整表单 | 从零搭建,带表达式和重试策略 |
| 导入文件 | 打开别人发给你的 .pcwf.json | 它到达时是停用的、带新 id,所以在你读过之前不会运行 |
激活模板会把它克隆成一份带新 id 的可编辑副本,所以改动它永远不会碰到原件。
触发器:什么会唤醒工作流
工作流监听流经 IDE 的事件。引擎订阅应用的内部事件总线,并把每个事件映射到一种触发器类型。 共有二十五种,而且一个工作流可以带一个主触发器加上任意多个额外触发器:
| 类别 | 触发器 |
|---|---|
| Git | Push(没有分支字段)、commit(仅来自「项目」界面) |
| 文件 | 保存、创建、删除、重命名 |
| 项目与构建 | 项目打开、项目关闭、构建完成、运行完成、终端命令完成 |
| 部署与数据 | 部署完成、部署失败、数据库查询已执行 |
| 其他模块 | API Tester 响应、设计已导出、AI 代理改动了文件、AI 代理完成一轮 |
| 来自手机本身 | 快捷方式、快速设置磁贴、分享的文本、分享的文件、应用回到前台 |
| 串联与手动 | 检测到错误(构建或运行出错、某次工作流运行失败、AI 代理运行的终端命令失败)、手动 |
过滤器是类型化的,这相对早期版本是个实打实的变化:每个触发器都声明自己的字段,你用 运算符——等于、包含、以…开头、匹配、路径通配——按字段比对值。它不再是在事件文本里做子串 搜索。而且因为没人能一次就把过滤器写对,编辑器提供了一个捕获下一个事件的按钮:你做 一次那件事,它就把触发器携带的真实负载展示给你,让你照着真实存在的东西写过滤器。
并非每种类型目前都有东西在发出它。其中两种今天永远不会触发:项目关闭和AI 代理完成一轮。 push 事件不带分支名,所以按分支的过滤器永远匹配不上,17 个模板中有两个(推送到 main 时自动 部署、推送到 main 之后跑测试)就是这样过滤的。编辑器不会把它们藏起来,而是在问题面板里提醒你: 这个工作流用了一个今天永远不会触发的触发器。
定时:手机上的 cron,无需服务器
这是「无服务器自动化」变得具体的地方。任何工作流都可以带一个或多个计划:一个预设间隔(每 15 分钟、每小时、每 6 小时),或者
一条五字段 cron 表达式,支持通配符 *、列表 N,M、范围
N-M 和步进 */N。输入时,界面会显示下一次触发时间,或告诉你表达式有误。
值得了解的三件事:
- 夏令时已处理好。 计划使用设备的时区(没有时区选择器)。春季那个不存在的时刻,在跳变时触发;秋季那个 出现两次的时刻,只触发一次。这是经过测试的。
- 错过时的策略。 由你选择:跳过设备关机期间该跑的,或者应用再次启动时补跑一次。一次—— 不是长周末的那四十八次。
- 设备条件。 任意网络、仅 Wi-Fi 或不限;仅充电时;电量低时不跑;仅设备空闲时。条件会 延迟运行而不是取消它,界面上就是这么写的。
还有一条不太好听的实话:安卓不会比每十五分钟更频繁地执行后台任务。低于这个值的间隔会被 抬高,应用会给出确切数字。低于这个值的 cron 没人会去抬高,所以唯一属实的说法是:没有 保证——界面写的正是这句,而不是一个编出来的数字。
计划会被持久化,并在应用启动时重新排队,所以进程被杀不会悄悄清空你的自动化。要修改一个计划, 就删掉它再新建一个。
分支、循环与子工作流
编辑器不是一排步骤的列表。共有七种步骤,其中六种是控制流,而且分支可以嵌套在分支里: 你搭出来的是一棵树。
- if / else —— 两个分支。条件是一棵树而不是单个槽位:
And、Or、Not可嵌套, 所以「测试通过且分支是 main」是一个条件,而不是两个工作流。 - 并行 —— 同时 N 个分支,三种汇合方式:全部完成、最先完成的一个、或最先成功的一个。 后两者会取消落败分支,让它们停止产生副作用。
- 遍历 —— 遍历一个列表,每项有别名、迭代次数有安全上限,并可选择同时运行多少次迭代。
- try / 失败时 —— 如果第一个块中有任何失败,第二个块就会运行,错误消息绑定到你命名的 变量上。
- 子工作流 —— 在本次运行中运行另一个完整工作流,带有自己的输入。正是它把一个长工作流 变成可复用的零件。
- 等待 —— 等一段时间,或者直到某个事件发生,时间作为上限。是「等部署结束」而不是 「等两分钟然后祈祷」。
而且根本不用加控制步骤:每个动作步骤都可带自己的可选条件。为假则跳过该步骤,无需把它包进整个 if / else。
十五个动作,个个接通
动作步骤有十五个,而且十五个全都接到了真正会执行的实现:运行命令、HTTP 请求、git 操作、部署、数据库查询或备份、读取/写入/检查文件、在编辑器中打开文件、用 AI 分析或生成、 转换一个值、设置变量,以及通知。
十五个都有实现,这不是展示层面的细节:有一个测试会变红并点名任何失去实现的类型。背后没有 实现的类型会大声失败,而不是悄悄报成功。
有几个限制值得了解。部署步骤只会触发 Render、Netlify 和 DigitalOcean(分支或环境会被记录,
但不会被采用)。git 步骤有七种操作:status、commit、push、pull、checkout、log 和 diff。
数据库查询要指明你的 Neon、Supabase、Turso 或 Upstash 连接之一。而设置变量把它的值作为
{{step.<id>.output.value}} 返回,并不会创建 {{var.name}}。
一个步骤是否具破坏性,是拿着它的参数算出来的,而不是看类型:git status 不是
git push,SELECT 也不是 DROP。把整个类型标为破坏性,会连 status 都要确认,而
事事都要确认只会教人不看就点同意。
在步骤之间传递数据
步骤共享一个上下文,任何字段都可以用双花括号表达式引用另一个步骤:
| 表达式 | 解析为 |
|---|---|
{{var.name}} | 已声明的输入,或 try 步骤的错误变量 |
{{step.<id>.status}} | 某步骤的状态 |
{{step.<id>.output.json.items[0].name}} | 输出中的某个字段,可深入 JSON 内部 |
{{step.<id>.error}} | 某步骤的错误消息 |
{{item.<alias>}} | 当前迭代的元素 |
{{trigger.<field>}} | 触发它的事件的类型化负载 |
{{secret.NAME}} | 已存储的密钥。终结值:无法深入其内部 |
外加十三个可链式过滤器:lines、first、last、trim、upper、lower、length、
json、default、split、join、date、replace。所以某命令输出的第一行就是
{{step.sh.output.stdout | lines | first | trim}}。
过滤器的参数总是写在引号里,例如 replace:"a":"b"。无法解析的表达式会故意返回空字符串,
这样对一个从未执行的分支中的步骤的引用就不会让整次运行崩掉。
可靠性:重试、超时,以及失败时怎么办
每个动作步骤都接受重试策略(等待可为固定、线性或指数,并有等待上限)和超时,而每个 步骤都有失败时怎么办的策略:中止运行或继续。
两个吃过亏才知道的细节:
- 失败后继续不会染色整次运行。 该步骤保持红色并带着它的错误,但运行结果是绿色的——
和 GitHub Actions 里
continue-on-error做的区分一样。 - 超时算作失败。 该步骤以「已超时」的标记返回,如果还有剩余重试次数,就会再试一次。
而且步骤可以关闭而不必删除,这正是调试时你想要的,而不是删掉再重写一遍。
除此之外,不必每调一个参数就跑完整个工作流(连带它的部署和通知),你可以用固定下来的数据 作为上下文,单独测试一个步骤。无法被模拟的步骤就不会被模拟:按钮会改为「真实运行此 步骤」并先行询问。一个什么都没跑就说「没问题」的按钮,比没有按钮更糟。
权限与密钥
工作流会声明它被允许做什么:访问网络、写文件、运行命令,以及一份它可以访问的域名清单。 实现会在动手之前检查,拒绝时会说明是哪个权限、本来要运行什么,以及在哪里修改。子工作流 继承权限的交集:它无法打开父流程关闭的东西。
它不是沙箱,界面上也这么写:能编辑这个工作流的人就能解开这条安全带。它防的是疏忽——你对
AI 开放的工作流、别人发给你的工作流,或者某人「就试一下」粘贴后忘了删的那条 curl。
密钥存放在一个按账户隔离的加密存储里。你用 {{secret.NAME}} 引用它们,值再也不会
显示,连它自己的页面上也不会。它们只在真实运行时才解析;遮蔽覆盖所有已存值,而不只是某个
步骤读过的;而且发生在写入数据库之前,而不是绘制界面时——绘制时才遮蔽就太晚了,值已经
在文件里和任何备份里了。
可供检视的运行历史
每次已结束的运行都被完整记录:每个步骤的结果、耗时、需要几次尝试,以及出错时的错误信息。已结束的 运行在应用关闭后依然保留;而安卓杀掉进程时仍在进行中的运行不会留下记录,shell 步骤的日志也不会保存。 活动标签页是跨所有工作流的视图,可按状态、日期、工作流以及错误 文本筛选。
保留策略由你设定:默认 100 次运行、30 天,可设 1 到 1000 次运行、1 到 365 天。
分享一个
工作流以 .pcwf.json 文件的形式传递。不随行的有:运行历史、固定输出、计划和开关。
到达的那份是停用状态并带有新 id。
被标记为密钥的参数值在写入文件前会被清空并被列出,好让打开它的人知道要填什么。
{{secret.X}} 这样的引用会随行:那是一个名字而不是密钥本身,清掉它会把工作流彻底弄坏。
其余内容都原样随行,包括 HTTP 请求头和命令,所以分享前请检查一下文件。
用大白话描述它
如果你不想手动拼装步骤,就写一句话。模型的回答会在可修正处被修正,经过 linter 检查并 进行空跑,然后在保存任何内容之前把结果展示给你。你也可以请它修改你已有的一个:回答会 合并上去,保留 id、开关和日期,并把 diff 展示给你。
如果你没有配置模型,有一个本地启发式兜底——对还没填密钥的人来说,那是唯一能用的东西。发给 模型的文档不包含任何密钥参数的值,它们被替换为占位标记。
反过来也一样:任何你勾选为「可供 AI 代理使用」的工作流都会作为工具暴露在聊天里,代理可以 调用它。上面的生成器是免费的;让 AI 聊天创建或更新工作流则是 Pro 功能。
你的自动化留在你的设备上
定义、历史和计划都存放在手机上的本地数据库里。定义可以备份到云端以便恢复(云同步,Pro 功能),但绝不会
为了运行你的自动化而从云端读取任何东西:引擎在本地运行,就这样。历史和计划完全不同步:
历史是设备本地的,计划是各设备各自的 WorkManager 状态。
最后一句实话:这里的分支是一棵嵌套的树,而不是你在画布上连线的节点。没有 N 路 switch,也没法把一个分支接到更下面的某个特定节点。同样也没有 webhook 触发器,工作流也不能 从应用市场安装或发布到应用市场(安装按钮是禁用的)。分享自己的工作流,就是分享那个文件。
PocketCode 正在前往 Google Play 的路上,把一个完整的自动化引擎——二十五种触发器、分支、 手机上的 cron、权限和密钥——带进你写代码和发布代码的同一个应用里。 加入预注册,成为最早在自己设备上试用它的人之一。
工作流