☰
Native SDK 自动化指南:用 `native automate` 驱动、断言与调试桌面应用运行时
2026/9/28 8:09:19 网站建设 项目流程
  • 桌面应用
  • 跨平台

【免费下载链接】native

Toolkit for building native desktop apps

项目地址:https://gitcode.com/gh_mirrors/ze/native
点击查看免费下载

导读

Native SDK(Zig 实现的跨平台桌面应用工具包,仓库根目录见 README.md)为每个启用自动化的应用内嵌一个自动化服务器——无论是原生渲染(retained-canvas / gpu_surface)应用还是 WebView 壳应用。它通过.zig-cache/native-sdk-automation/下的文件型 IPC(文件投递箱协议,dropbox protocol)工作,专为冒烟测试、带 GUI 会话的 CI 校验与快速运行时巡检设计:可读取可访问性快照、沿真实输入路径驱动 retained 组件、生成确定性的参考渲染截图、做就绪/状态断言,并完成桥接(bridge)往返。本文基于 skill-data/automation/SKILL.md,并结合 src/automation/ 的源码实现,给出完整、可复制的实操指南。

注意:这不是浏览器 DOM 自动化。它报告的是运行时/窗口/组件状态,驱动 retained-canvas 组件,并可以要求运行时重载或派发桥接请求。若要测试可选的 WebView 路径的 DOM,请使用前端框架的测试或对 dev server 使用浏览器自动化工具。

自动化能验证什么、不能验证什么

能验证:

  • 启用自动化的应用已启动并发布ready=true;
  • 运行时加载了预期的应用名、源码类型与窗口元数据;
  • 主窗口存在且处于聚焦/打开状态;
  • JavaScript↔Zig 桥接可通过native automate bridge完成一次请求往返;
  • 内建窗口/WebView 命令可被冒烟测试驱动;
  • 运行时接受重载请求;
  • retained-canvas(gpu_surface)视图的真实像素:native automate screenshot <view-label>通过确定性 CPU 参考渲染器把视图当前 canvas 帧渲染成 PNG 产物。同一场景的两次抓取字节一致,因此截图可支撑 golden-image 或“UI 是否变化”的检查。

不能验证:

  • WebView 内容的截图:screenshot仅覆盖gpu_surfacecanvas 视图,没有 DOM/WebView 像素捕获;
  • 任意 DOM 查询与点击;
  • 浏览器网络断言。

从快照数据模型(src/automation/snapshot.zig)看,快照内容由Input结构体承载:窗口(Window)、视图(ViewInfo,区分gpu_surface与webview两种kind)、组件(Widget)、命令与应用菜单目录(commands/menus)、托盘(trays)、音频/视频播放状态(audio/video)以及诊断信息(Diagnostics)。这决定了“能验证”的边界正是快照里被明确建模的那些状态。

前置条件:如何启用自动化

用-Dautomation=true构建并运行应用。生成的示例通常直接暴露该选项:

zig build run -Dplatform=macos -Dautomation=true

仓库示例可能有专门步骤:

zig build run-webview -Dplatform=macos -Dautomation=true zig build test-webview-smoke -Dplatform=macos

Runner 必须把自动化服务器传入RuntimeOptions(对应 src/runtime/api.zig 中的automation: ?automation.Server字段):

const server = native_sdk.automation.Server.init(io, ".zig-cache/native-sdk-automation", "My App"); var runtime = native_sdk.Runtime.init(.{ .platform = my_platform, .automation = server, });

Server.init的签名见 src/automation/server.zig:三个参数分别是io、投递箱目录(默认.zig-cache/native-sdk-automation)和用于标识的 title。

未用-Dautomation=true构建的应用通常会忽略自动化文件——自动化是编译期门控的:没开选项的应用不创建投递箱目录、不发布快照、不消费命令。

命令一览

CLI 总入口是native automate <command>(仓库构建版为zig-out/bin/native automate <command>,命令表定义在 tools/native-sdk/automation.zig):

native automate wait native automate assert 'gpu_nonblank=true' 'role=button name="Reset"' native automate assert --absent 'error event=' native automate list native automate snapshot native automate reload native automate screenshot inbox-canvas native automate screenshot inbox-canvas 2 native automate widget-action canvas 2 press native automate widget-click canvas 3 native automate widget-hold canvas 3 native automate widget-context-press canvas 3 native automate widget-drag canvas 4 0.25 0.82 native automate widget-wheel canvas 5 18 native automate widget-key canvas tab native automate widget-key canvas cmd+c native automate widget-pinch canvas 1.5 native automate widget-pinch canvas 0.5 120 80 native automate profile on native automate profile off native automate bridge '{"id":"smoke","command":"native.ping","payload":{"source":"automation"}}'

Action枚举(src/automation/protocol.zig)是这套命令的协议面:reload、wait、resize、screenshot、bridge、native_command、widget_action、widget_click、widget_hold、widget_context_press、widget_context_menu、widget_drag、widget_wheel、widget_key、widget_pinch、menu_command、shortcut、tray_action、focus_view、focus_next_view、focus_previous_view、profile、provenance。对应 CLI 的usage文本在 tools/native-sdk/automation.zig。

标准工作流:从启动到驱动组件

  1. 以自动化模式启动应用。
  2. native automate wait阻塞直到snapshot.txt出现ready=true。
  3. 用native automate assert '<pattern>' ...做状态检查,或用native automate snapshot目检应用/窗口/源码元数据。
  4. native automate list查看窗口摘要。
  5. native automate bridge '...'做桥接往返检查。
  6. native automate widget-action <view-label> <widget-id> <action> [value]驱动 retained canvas 组件动作。set_text走的是与真实键入完全相同的输入路径(聚焦 → 全选 → 文本输入事件),因此 TEA 应用的on_input镜像会收到编辑、模型状态与屏幕上的字段保持一致——它不是只写表现层。
  7. native automate widget-click <view-label> <widget-id>驱动指针式 retained 组件路由。widget-hold <view-label> <widget-id>以同一路径驱动按下并保持——指针按下、保留的 hold 定时器触发、然后释放被抑制——所以on_holdMsg 可被真实驱动(目标没有on_hold时退化为真实长按的点击)。widget-context-press <view-label> <widget-id>是次键点击:弹出组件的上下文菜单,或当路由未声明菜单时立即派发on_hold。
  8. native automate widget-drag <view-label> <widget-id> <start-x-ratio> <end-x-ratio> [start-y-ratio end-y-ratio]用于连续指针控件(比例为 0..1 的视图内相对坐标)。
  9. native automate widget-wheel <view-label> <widget-id> <delta-y>用于 retained 组件滚动输入。滚轮目标必须是可交互/可滚动的组件——普通布局列或文本节点不是滚轮目标;应瞄准快照中出现的 scroll/list 组件 id。失败会以命名原因出现在快照里:error event=automation.widget_wheel name=WheelTargetUnknown|WheelTargetNotInteractive|WheelTargetHasEmptyBounds detail="<command args>"。
  10. native automate widget-key <view-label> <key> [text]向聚焦的 retained 组件发送键盘输入。key 支持修饰键和弦——cmd+a、cmd+c、cmd+v、cmd+x、ctrl+shift+arrowleft(cmd在所有平台上都映射为主快捷键修饰键)——因此全选/复制/剪切/粘贴和 shift 扩展选择都可驱动;复制之后,快照中组件行会显示实时选区selection=a..b,复制文本落到真实系统剪贴板(macOS 上即pbpaste可读)。
  11. native automate widget-pinch <view-label> <scale> [x y]对 gpu-surface 视图驱动触控板捏合手势:运行时派发真实的pinch_begin/pinch_change/pinch_end平台事件,其中一次 change 携带scale - 1。<scale>是手势的最终乘法缩放——累积手势缩放(1 + delta的乘积)精确落在这上面——1.5放大 50%,0.5缩到一半。可选锚点为视图局部坐标点,默认视图中心。应用通过 pinch 通道听到它(Options.on_pinch/ TS core 的pinchMsg)。
  12. native automate screenshot <view-label> [scale]把指定gpu_surface视图的 canvas 抓成screenshot-<view-label>.png(CLI 打印产物路径并等待文件出现)。
  13. 驱动应用菜单命令前,先检查快照的command id="..."目录与app-menu/app-menu-item行,证明运行中的应用加载了预期的app.zon或 runner 声明。然后用native automate menu-command <id>派发与真实菜单选择相同的.menu_command平台事件;该动词仍是原始事件注入器,因此快照的收到记录才是验证注册的方式。
  14. native automate tray-action <item-id>用于主状态项,或native automate tray-action <status-item-id> <item-id>用于显式项。两者都通过真实菜单栏点击发出的同一平台事件选择下拉行(命令源.tray)。活跃项以tray #status-id title="..." visible=... items=N加后续tray-item #item-id ...行出现在snapshot.txt中——菜单栏位于所有窗口捕获之外,因此这是每个模型驱动项的自动化证据。未知 id 对会以automation.tray_action进入派发错误环。
  15. native automate reload请求 WebView 重载。
  16. native automate profile on开启分阶段帧计时:开启期间,snapshot.txt携带一条frame_profile行,给出流水线各阶段(rebuild、layout、reconcile、emit、a11y、plan、patch、encode、present、host_decode、host_draw)的滚动 p50/p90/max 微秒数,每阶段带生命周期采样数(<stage>_n=)。驱动一些交互后,用native automate snapshot | grep -o 'frame_profile.*'读取帧时间花在哪里;profile off停止记录并移除该行。开启即开启一个新的采样窗口。

底层协议中,命令由Command.parse解析(src/automation/protocol.zig),wire 字符串与Action枚举一一对应;快照侧FrameProfileStage与FrameProfile结构(src/automation/snapshot.zig)承载 profile 数据。

快照断言(automate assert)

优先用native automate assert而不是snapshot | grep链:它会轮询,所以不需要 sleep,失败输出自带证据(每个缺失模式 + 快照尾部)。

native automate assert 'gpu_nonblank=true' 'role=button name="Reset"' 'count: 0' native automate assert --timeout-ms 10000 '4 open' native automate assert --absent 'error event=' 'dispatch_errors=[1-9]'

语义:

  • 每个参数都是必须匹配snapshot.txt中某处的正则。命令以 100ms 间隔轮询直到全部匹配,然后退出 0。
  • --timeout-ms <n>限定轮询时间(默认 30000)。超时打印每个未匹配模式的missing: <pattern>、快照最后 20 行,并以非零退出——CI 友好,无需包装脚本。
  • --absent反转整个调用:每个模式必须不匹配(轮询直到消失)。要同时断言存在与不存在,运行两次调用。
  • 支持的正则子集:字面量、.、后置*+?、行锚点^/$、字符类[a-z]/[^0-9],以及\d \w \s(含大写取反)。不支持分组与交替——改为传多个模式。
  • 用单引号包裹模式,让 shell 不动"、$和\d。

从实现看(tools/native-sdk/automation.zig),assert 的实现参数是:轮询间隔assert_poll_interval_ms = 100、默认超时assert_default_timeout_ms = 30_000、失败尾部行数assert_tail_lines = 20、模式上限assert_max_patterns = 32。正则匹配器是一个小型自研 grep 式子集(matchesPattern/matchHere/matchRepeat/atomMatches/escapeMatches/classMatches),配套单元测试见 tools/native-sdk/automation.zig,例如count: \d+匹配status count: 42 open、.*=true$匹配gpu_nonblank=true、无效模式(*x、a\、[abc、^*)被拒绝。

截图与确定性语义

screenshot <view-label> [scale]要求运行时通过确定性 CPU 参考渲染器栅格化视图当前的 retained canvas 帧——与 Linux 软件呈现相同的像素路径——并发布为无压缩 PNG:.zig-cache/native-sdk-automation/screenshot-<view-label>.png。文件原子写入(临时文件 + rename),因此其存在即表示 PNG 完整(publishScreenshot实现见 src/automation/server.zig,先写.tmp再 rename 到位)。

确定性语义:

  • 截图默认按 scale 1 渲染,与显示器的 backing scale 无关,因此同一台机器上未变化的场景每次抓取都产生字节一致的 PNG。显式传 scale(如2)可获得高 DPI 像素尺寸。
  • 截图使用实时 retained 场景,包括实时设计 token 与平台文本测量(macOS 上为 CoreText):布局与屏幕上一致。字形由参考渲染器用内置字体面栅格化,而非平台字体光栅化,所以截图是确定性的布局/结构/颜色信号,而非平台字体渲染信号。
  • 跨机器字节一致仅在文本度量确定性的地方(null 平台的估算器)有保证。在带原生文本测量提供者的平台上,文本宽度可能随 OS 版本变化,因此应在同一台机器上比较截图,或断言属性(尺寸、变化/未变化)而非跨机器的精确字节。
  • OS 级捕获(macOS 的screencapture -x)不能替代:在无屏幕录制权限的 shell 中它退出 0 却静默返回只有壁纸、没有应用窗口的图片。若你 shell 出去做真实像素捕获,先验证图片非空白/非壁纸再信任它;automate screenshot+ 语义快照才是可靠组合。

安全边界:截图文件名通过protocol.screenshotFileName生成(src/automation/protocol.zig),标签名中[A-Za-z0-9._-]之外的字节被替换为-,且标签上限max_screenshot_label_bytes = 64,保证文件名永远无法逃出自动化目录(测试验证../evil→screenshot-..-evil.png、a/b→screenshot-a-b.png)。

桥接冒烟测试模式

请求必须是带 ID、command、payload 的 JSON:

native automate bridge '{"id":"smoke","command":"native.ping","payload":{"source":"automation"}}'

自动化以 originzero://inline发送请求。应用的桥接策略必须允许该 origin,否则调用会被permission_denied拒绝。打包资产 origin 下,应用代码通常允许zero://app;自动化冒烟测试只在需要时添加zero://inline。

典型native.pinghandler 的响应形状:

{"id":"smoke","ok":true,"result":{"message":"pong","count":1}}

命令失败时检查桥接错误码:

  • unknown_command:无已注册 handler 或命令名错误。
  • permission_denied:origin 或权限策略阻止了它。
  • handler_failed:Zig handler 返回错误或无效 JSON。
  • payload_too_large:请求超过桥接限制。

CLI 侧,bridge会先删除旧的bridge-response.txt、发送命令、再等待响应产物出现(tools/native-sdk/automation.zig);响应由Server.publishBridgeResponse写入(src/automation/server.zig)。

文件协议:投递箱里有什么

默认目录是.zig-cache/native-sdk-automation/,相对于 CLI 的当前工作目录解析——请从应用项目目录(应用启动处)运行native automate。该目录由运行中的应用创建,CLI 从不创建:从错误 cwd 发出的命令会响亮失败(error: no automation dir at <abs path>),而不是排队进一个没有应用读取的目录;每条排队命令都会打印它写入的绝对目录——命令看似没动静时检查这一行。

文件清单:

  • snapshot.txt:应用名、就绪状态、源码类型、源码大小、窗口元数据、可访问性摘要。ready=true行还携带protocol=<n>(CLI/应用握手:协议版本不是自己的时 CLI 拒绝快照——以及向存活应用排队命令——并同时命名两个版本;修复办法是重建过时的一侧并对比native version)、dispatch_errors=<total>与dropped_trace_records=<total>;最近的降级 handler/update 错误以error event=<tag> name=<ErrorName> timestamp_ns=...行出现——handler 错误不再退出应用,因此用 grep 来发现它发生。profile on激活时,一条frame_profile <stage>_p50_us=... <stage>_p90_us=... <stage>_max_us=... <stage>_n=...行跟随头部给出分阶段帧计时。头部还携带markup_watch=armed|off——标记热重载 watch 是否已武装(仅当应用以.markup带watch_path与io接线、或通过fragment_watch注册了编译片段时才武装——即 Debug 开发构建)。
  • windows.txt:窗口列表。
  • command.txt(历史遗留单槽)+command-<n>.txt:CLI 写入、运行时消费的命令输入。当前协议是编号队列:command-<n>.txt条目取代了会因快速连续写入而互相覆盖的单槽command.txt。槽位单条进入,应用每呈现一帧消费一条;native automate <command>会等待运行中的应用消费它,成功时打印delivered <action> -> <dir>——它拒绝/响亮失败而不是静默覆盖未消费命令,应用永不消费时以非零退出。
  • bridge-response.txt:最近一次桥接响应。
  • screenshot-<view-label>.png:gpu_surface 视图的确定性参考渲染 PNG,由screenshot命令写入。

运行时轮询命令队列,处理完一条命令后写入done(以删除队列条目文件作为消费确认,见 src/automation/server.zig 的takeCommand)。

快照头部由snapshot.writeText手写(src/automation/snapshot.zig):ready=true protocol=0x... frame=<n> commands=<n> runtime_uptime_ns=<n> dispatch_errors=<n> dropped_trace_records=<n> publisher_pid=<n> markup_watch=<armed|off>。publisher_pid是发布应用的 pid——投递箱文件跨构建与运行持久存在,因此 CLI 在信任快照前用实时进程表校验它:发布者已死或缺失即视为陈旧文件,响亮地作为 "stale" 服务而非当前状态(snapshotLiveness/pidIsAlive,tools/native-sdk/automation.zig)。

协议指纹与版本握手

protocol=字段是 CLI↔应用握手:发布应用在构建时烘焙自己的协议指纹(src/automation/protocol.zig 的fingerprint,对协议表面描述的 comptime Wyhash)并在每个快照头部盖章;CLI 拒绝指纹不是自己的快照——因此过时的native二进制驱动新构建的应用(或反之)会响亮失败并命名两个指纹,而不是静默读取昨天的状态。semantic_epoch(当前为 4,src/automation/protocol.zig)是layoutDescription看不到的语义变更的逃生舱(如同字节的语义断裂、快照文本格式变更、动词拼写变更)。若报告协议不匹配(或快照无协议版本):native二进制与应用由不同框架版本构建——重建过时一侧(过时的zig-out/binCLI 副本是经典原因;native version打印该二进制构建自的 commit)。

陈旧实例守卫:自动化动词在发布应用的进程早于zig-out/bin中最新的二进制构建时就打印响亮警告——旧一次运行遗留的实例在冒充新构建。杀掉它并重新启动新二进制,再信任任何快照(warnStaleInstanceIfDetectable,tools/native-sdk/automation.zig)。

命令队列的诚实性

sendCommand(tools/native-sdk/automation.zig)贯彻三条诚实规则:目录不存在就响亮拒绝(应用创建,绝不 CLI 创建);对已在其他协议上的存活发布者拒绝排队;队列满(max_queued_commands = 8,src/automation/protocol.zig)时以消费节奏重试约 10s 后响亮拒绝并命名深度,绝不覆盖。条目以独占创建声明(flags.exclusive),命名竞争失败则重扫队列取下一序号,因此背靠背或并发调用永不互相覆盖。消费以“文件被删除”为确认(awaitCommandConsumed),约 10s 预算:消费通常只需一个呈现帧,耗尽预算意味着应用退出、冻结或停止呈现——这正是诊断信息。

调试自动化失败

若native automate wait超时且完全没有snapshot 文件,它会打印一条教学式错误,命名它监视的自动化目录,并指向-Dautomation=true与工作目录——从这条消息开始排查。否则:

  1. 确认应用仍在运行。
  2. 确认它是以-Dautomation=true构建的。
  3. 确认 runner 把automation传入了Runtime.init。
  4. 检查.zig-cache/native-sdk-automation/snapshot.txt。
  5. 删除.zig-cache/native-sdk-automation/中的陈旧文件并重启应用。
  6. 用更多追踪运行,例如zig build run -Dtrace=all。

若 CLI 报告自动化协议不匹配(或快照无协议版本):native与应用由不同框架版本构建——重建过时一侧。

若snapshot说没有应用连接:

  • 自动化目录可能还不存在;
  • 应用可能运行在不同的工作目录;
  • 应用可能是未开自动化的构建;
  • 应用可能还没到达运行时启动。

若桥接自动化失败:

  • 检查命令名拼写;
  • 检查应用 handler 注册;
  • 检查桥接策略 origin 是否含zero://inline;
  • 检查运行时权限;
  • 检查 handler 返回有效 JSON。

命令看似没动静?检查排队命令打印的绝对目录行——应用从不消费时,CLI 会在约 10s 后以error: the app never consumed <action>响亮失败。

CI 与冒烟测试

用自动化获得最小的集成置信度:

zig build test-webview-smoke -Dplatform=macos

一个好的冒烟测试:

  1. 以-Dautomation=true与-Djs-bridge=true构建示例。
  2. 在可 GUI 的会话中启动应用。
  3. 等待就绪。
  4. 验证快照元数据(用相关模式automate assert)。
  5. 发送native.ping。
  6. 若应用启用内建窗口/WebView 则驱动它们。
  7. 超时或桥接响应异常即失败。

以native init --full脚手架的应用会把上述流程作为.github/workflows/ci.yml打包(零配置默认脚手架跳过 CI):一个 null-platformzig build test任务加一个 Linux Xvfb 冒烟任务——启动二进制、运行automate wait、用automate assert断言快照、并检查非空的automate screenshot产物。扩展那个文件,而不是手写 grep 链。

不要用自动化做穷尽式 UI 测试——它是运行时与桥接冒烟层。相关集成证据可见仓库测试 src/runtime/automation_liveness_tests.zig 与 src/runtime/automation_snapshot.zig。

补充说明

  • 自动化是编译期门控的:未以-Dautomation=true构建的应用忽略自动化文件。
  • 截图只覆盖 retained-canvas(gpu_surface)视图;WebView 像素不被捕获。
  • WebView DOM 交互有意排除在本文件型自动化层之外。
  • 需要应用架构、桥接策略、打包与调试上下文时,使用native skills get core --full。
  • 若需要会话级记录/回放(record/replay),native automate record --out <session.journal> -- <app command...>与native automate replay <session.journal> [--verify|--no-verify] -- <app command...>可用(tools/native-sdk/automation.zig),通过NATIVE_SDK_SESSION_RECORD/NATIVE_SDK_SESSION_REPLAY环境变量武装应用 runner。
  • 桌面应用
  • 跨平台

【免费下载链接】native

Toolkit for building native desktop apps

项目地址:https://gitcode.com/gh_mirrors/ze/native
点击查看免费下载
上一篇:Operator SDK v1.28.0 版本深度解析:依赖升级、Ansible 修复与 Scorecard 非 root 化改造
下一篇:免费网盘直链下载助手:八大网盘一键获取下载地址的终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询