- 桌面应用
- 跨平台
【免费下载链接】native
Toolkit for building native desktop apps
导读
Native SDK 是一套用于构建原生桌面应用(native desktop applications)的完整工具链:应用默认以 TypeScript 编写应用逻辑(src/core.ts)、以声明式 Native markup(.native文件)描述界面,并在构建期被预先检查、编译为真正的原生机器码,最终交付的二进制中不包含任何浏览器、WebView、JS 运行时或解释器。本指南围绕仓库内的 Native SDK 技能发现文档 展开,系统讲解核心心智模型、快速开始流程、三文件应用骨架、app.json清单、CLI 命令全景、面向 AI Agent 的 skill 加载机制以及内嵌的自动化服务器;读完你将掌握如何初始化、开发、校验、测试、自动化驱动一个 Native SDK 应用,并理解其底层实现依据(CLI 入口、核心技能、CLI 包说明)。
Native SDK 是什么:核心心智模型
默认创作路径是 TypeScript 应用逻辑 + 声明式 Native markup 视图。TypeScript 核心(src/core.ts)会在构建前被检查和编译为原生代码,因此最终二进制里没有浏览器、WebView、JS 运行时或解释器——引擎由 Native SDK 自己用 Zig 实现,把每一帧像素绘制进真实的 OS 窗口。
这条路径的几个关键心智模型(详见 core 技能):
- 三个事实源文件:默认应用只有三个文件——
src/core.ts(Model、Msg、update)、src/app.native(UI)、app.json(清单),零构建配置。 - Markup 只绑定、不修改状态:Native markup 绑定模型值并派发类型化消息,只有
update能改变状态。 - Node 只是构建/检查/开发工具,不是应用运行时。
App是底层产品/运行时接口,由生成的接线、Zig-core 应用、WebView 外壳和扩展使用;Runtime拥有事件循环、窗口、桥接派发、安全检查、自动化、追踪、平台服务和窗口状态。app.json是默认清单:身份、图标、窗口、前端资源、Web 引擎、权限、桥接策略、安全策略与打包输入;遗留的app.zon继续受支持。
Zig 的地位:显式选择的一等公民
Zig 是 Native SDK 工具链自身的实现语言,同时也是一等公民的应用核心备选方案——但必须是显式选择(native init my_app --template zig-core),不是从 SDK 实现推断出的默认语言。仓库中大量*.zig文件(如 CLI 入口、运行时)证明的是“工具链用 Zig 写”,而非“应用默认用 Zig 写”。判断一个既有应用属于哪条路径很简单:看到src/main.zig意味着它显式使用了 Zig-core 模板;看到frontend/目录则意味着它属于 WebView 前端外壳。
WebView:可选的网页内容集成路径
当产品的一部分是网页时,WebView 表面与原生画布并存:native init --frontend next|vite|react|svelte|vue会生成 WebView 前端外壳。这条路径用于嵌入既有 web 内容或托管既有 web 前端,而不是新应用的默认起点。原生渲染表面与 WebView 共享窗口、策略、生命周期、命令与平台服务,一个应用可以混合两者。
自动化服务器:每个应用都内嵌
每个 Native SDK 应用都内嵌一个确定性自动化服务器,Agent 可以对其运行中的应用做快照(snapshot)、驱动(drive)与截图(screenshot)——这是后文“自动化”章节的伏笔,也是本 SDK 面向 Agent 工作流的重要设计。
平台成熟度
桌面是成熟面:macOS 支持最深,Linux 与 Windows 在 CI 中被持续演练;移动端嵌入仍属实验性。
快速开始:从零到原生窗口
按照 skills/native-sdk/SKILL.md 与 CLI 包说明,三步即可跑起一个原生窗口:
npm install -g @native-sdk/cli native init my_app cd my_app native dev- 安装:
npm install -g @native-sdk/cli不执行任何脚本——native二进制以按平台拆分的可选依赖(@native-sdk/cli-<platform>)交付,包本身携带应用构建所需的 SDK 源码,因此安装后native init与native dev可以离线工作。首次构建时,固定的 Zig 工具链会被拉取到~/.native/toolchains/,除非 PATH 上已有兼容的zig(package.json 显示 CLI 版本为 0.10.1,要求 Node >= 24)。 - 脚手架:
native init my_app生成三文件应用——app.json、src/app.native(markup 视图)、src/core.ts(Model、Msg、update)。已有app.zon清单的项目继续受支持。 - 运行:
native dev构建并启动应用,打开一个带可运行计数器的原生窗口;src/app.native在应用运行期间热重载并保留状态。
编辑既有应用前务必先检查app.json或app.zon与src/目录,保留其已使用的核心语言(不要因为 SDK 示例里都是 Zig 就给默认 TypeScript 应用添加 Zig 源码)。
三文件应用骨架:TypeScript 核心契约
默认 TypeScript 核心(ts-core 技能)是确定性的应用逻辑层,契约如下:
export interface Model { /* 只读数据字段 */ } export type Msg = | { readonly kind: "add" } | { readonly kind: "toggle"; readonly id: number }; // 每个“可能发生的事”一个分支;至少两个分支 export function initialModel(): Model { /* 纯函数 */ } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { // 每个分支一个 case;switch 必须穷尽(缺一个分支就是构建错误) } }要点:
update是纯函数:同步地把模型推进到下一个状态,必要时返回[Model, Cmd<Msg>]描述效果——效果是数据,由运行时在模型提交后执行,并把结果作为Msg派发回来。initialModel也可以返回同款二元组以在安装时执行一次启动效果;需要周期任务的导出subscriptions(model): Sub<Msg>。- 导出单参模型辅助函数即派生绑定:
export function doneCount(model: Model): number编译为公开原生函数,同时自动成为 markup 可绑定的模型声明({doneCount}),派生值无需模型字段。 - “派生,不要存储”:模型只存真相源状态(原始条目、当前过滤器、草稿文本),凡是可从这些算出的(计数、汇总、过滤视图、格式化字符串)都写成派生辅助函数,绝不缓存进模型字段——缓存值必须在每个
update分支里手工维护,漏一个就过期;派生函数不会。 - 文本即字节:
string模型字段被禁止(NS1024),统一用Uint8Array(配合asciiBytes/utf8Bytes),保证一种文本表示。 - 子集约束:核心编译时采用封闭 TypeScript 子集,禁用两类构造:二进制无法承载的生态(npm 包、Node/DOM API、正则、JSON、Promise、生成器、
eval——因为不内置 JS 引擎,对应 NS1013/NS1040/NS1002/NS1035 等教学错误),以及会破坏核心保证的构造(纯度与确定性、固定形状、单一文本表示、函数即声明、无运行时标签的静态类型)。违反即得到一条命名规则、修复方式与原因的教学错误,而不是含糊的编译失败。 - 服务边界:当普通 TypeScript 需要
fs/process/JSON/regex/Map/Date/class 等核心子集之外的能力时,放入src/services/**/*.ts(ts-services 技能),通过生成的类型化客户端@native-sdk/services调用;核心绝不 import 服务文件(NS1065)。
Native markup 视图:绑定与派发
src/app.native描述整个 UI:元素、布局、绑定、消息派发。markup 编译出的 widget 树与手写canvas.Ui(Msg)builder 视图完全同构——相同的结构化 widget id、相同的类型化处理表。Markup 永远不能修改状态:它绑定值、派发消息,所有逻辑都在应用核心(无论核心语言是哪种)。
<text-field text="{draft}" placeholder="New task…" on-input="draft_edit" on-submit="add" grow="1" /> <list-item on-press="open_note:{n.id}" label="{n.title}"> <text grow="1">{n.title}</text> </list-item>关键能力(详见 native-ui 技能):
- 表达式语法是封闭的:属性值取字面量或恰好一个
{表达式};表达式是纯且全的(无用户定义函数、无副作用、保证终止)。支持算术+ - * /(/恒产生 float,整数位置需要round()/floor()/ceil())、比较== != < <= > >=(排序仅限数字;相等比较任意两个值)、布尔and/or/not、++拼接,以及封闭的 17 函数库:fixed(x, digits)(0-6 位精确小数,half-away 舍入)、thousands(n)、percent(fraction, digits?)、date(ts)/time(ts)/datetime(ts)(unix 秒按 UTC 格式化)、upper(s)/lower(s)/trim(s)、min/max/abs、round/floor/ceil、plural(count, singular, plural)、pad(x, width)(mm:ss 计数器即{pad(minutes, 2)}:{pad(seconds, 2)})。边界:单个表达式 256 字节、64 个项、16 层嵌套。阅读时钟是效果——now()是教学错误,应在update/fx 中维护时间戳字段。 - 消息:
on-press、on-double-press、on-toggle、on-change、on-submit、on-dismiss、on-hold、on-hover-enter/on-hover-leave取tag或tag:{payload}形式,tag 必须是Msg联合的一个分支;on-input携带TextInputEvent(TypeScript 中来自@native-sdk/core/text);on-scroll携带ScrollState;on-reach-end是无限加载信号(自带迟滞:接近末尾 1 个视口触发一次,越过 1.5 视口后重新武装)。 - 元素词典:
row/column(flex 容器)、stack/panel/card(叠放容器)、scroll、list/grid、tabs/toggle-group/button-group/radio-group/breadcrumb/pagination、table > table-row > table-cell、dropdown-menu(锚定浮层)、accordion、alert/bubble、dialog/drawer/sheet(模态表面)、resizable/split(模型持有分割比例的on-resize回环)、tree(ARIA 树键盘导航)、text/badge/tooltip、text > span(富文本内联样式)、button/toggle-button/list-item/menu-item/toggle/switch/select/avatar、segmented-control、checkbox/radio/slider/progress、text-field/input/search-field/combobox/textarea、status-bar、separator/spacer、skeleton/spinner、icon(49 个编译期校验的内置描边图标)、media-surface/image(运行时注册的模型持有 id)、code(源码高亮)、markdown、stepper、timeline、chart > series、context-menu(单一声明、平台决定呈现)等。 - widget 预算:每个视图有固定容量(canvas_limits.zig):1024 个保留 widget 节点、64 KiB 保留 widget 文本、512 个声明的上下文菜单项、64 个图表系列/16384 个数据点、每帧 2048 条命令/8192 个字形/32 KiB 帧文本;同时最多挂载 16 个锚定浮层。溢出会响亮失败并给出教学诊断。自动化快照会报告
widget_nodes=N/1024 widget_semantics=N/1024 context_menu_items=N/512,便于监控余量。数据集规模的均匀行请用 windowed virtual list(ui.virtualWindow+ui.virtualList):运行时拥有视口数学,模型拥有数据,100k 行也保持视口级预算(参考 feed 示例)。
清单:app.json(与遗留 app.zon)
app.json是应用级行为的真相源;既有app.zon项目以 ZON 语法使用相同字段。核心技能给出了完整示例:
{ "$schema": "https://schema.native-sdk.dev/app/v1.json", "id": "com.example.my-app", "name": "my-app", "display_name": "My App", "description": "One line about the app, shown in the About panel.", "version": "0.1.0", "icons": ["assets/icon.png"], "platforms": ["macos", "linux"], "permissions": [], "capabilities": ["webview"], "frontend": { "dist": "frontend/dist", "entry": "index.html", "spa_fallback": true, "dev": { "url": "http://127.0.0.1:5173/", "command": ["npm", "--prefix", "frontend", "run", "dev", "--", "--host", "127.0.0.1"], "ready_path": "/", "timeout_ms": 30000 } }, "security": { "navigation": { "allowed_origins": ["zero://app", "http://127.0.0.1:5173"], "external_links": { "action": "deny" } } }, "web_engine": "system", "windows": [ { "label": "main", "title": "My App", "width": 960, "height": 640, "restore_state": true } ] }字段职责速览:
- 身份与品牌:
id(应用唯一标识)、name、display_name、description、version、icons。 - 平台与能力:
platforms、permissions(如"filesystem"、"credentials")、capabilities(如"webview"、"credentials")。安全默认是只列出需要的权限与能力。 - 前端:
frontend.dist/entry/spa_fallback描述打包资源;frontend.dev描述开发服务器(url、启动命令、ready_path就绪探测、timeout_ms超时)。为开发服务器使用精确的本地源;仅内联 HTML 源时才添加zero://inline。 - 安全策略:
security.navigation.allowed_origins允许列表控制主框架导航,external_links.action默认deny。内置对话框始终默认拒绝,需要显式builtin_bridge策略。 - Web 引擎:
web_engine = "system"用于小型应用与最小原生足迹(macOS 上为 WKWebView、Linux 上为 WebKitGTK);需要钉死 Chromium 平台或渲染一致性时用"chromium"并配套.cef配置与 CEF 布局。 - 窗口:
windows声明窗口(label、title、width/height、restore_state)。
零配置应用无需 eject 即可打包:native build后native package --target macos --archive直接工作(native eject只是让应用拥有构建文件,从不是打包前置条件)。
CLI 命令全景
native CLI 包说明 收录了全部命令;入口实现在 tools/native-sdk/main.zig:
| 命令 | 说明 |
|---|---|
native init [path] [--template <ts-core\|zig-core>] [--frontend <native\|next\|vite\|react\|svelte\|vue>] [--full] | 脚手架新应用(默认 TypeScript 核心 + Native markup) |
native dev [dir] | 构建并运行(markup 热重载;配置了前端时管理前端 dev server) |
native build [dir] | 构建 ReleaseFast 二进制到zig-out/bin/ |
native test [dir] | 运行应用测试套件 |
native check [dir] | 毫秒级校验src/**.nativemarkup 与app.json/app.zon是否符合模型契约,无需构建 |
native markup check\|lsp | 检查单个 markup 文件,或为编辑器提供诊断、补全与悬停 |
native eject [dir] | 将build.zig/build.zig.zon写入应用(拥有构建) |
native doctor | 检查宿主环境、WebView、清单与 CEF |
native validate | 按清单 schema 校验app.json(或app.zon) |
native package | 打包应用用于分发 |
native bundle-assets | 把前端资源复制进构建输出 |
native automate | 驱动运行中的应用:快照、widget、断言、截图、录制/回放 |
native skills list\|get <name> | 列出或打印内置 AI Agent 技能 |
native version | 打印 native 版本 |
默认 TypeScript + Native markup 应用的开发循环是:
native check # 校验 core.ts 子集 + markup + 清单 native dev # 构建并运行真实应用(markup 热重载) native dev --core # 最快的逻辑循环:核心跑在 node 的虚拟宿主下,纯逻辑无渲染器 native test # 运行应用测试面向 AI Agent:技能发现与按需加载
本仓库把面向 Agent 的知识做成了可安装、可发现、按需加载的技能系统。使用过npx skills add native-sdk的 Agent 在实现或讲解 Native SDK 工作前,应通过已安装的 CLI 发现并加载当前技能内容:
native skills list native skills get core native skills get native-ui native skills get ts-core仓库内的技能数据源即 skill-data/ 目录:
core(skill-data/core/SKILL.md):初始定位用;建立 TypeScript + Native markup 默认路径的心智模型,覆盖共享基础:项目结构、app.json与遗留app.zon、底层App/Runtime模式、前端集成、Web 引擎、JavaScript 桥接命令、权限、窗口、WebView、对话框、打包、调试与测试。native-ui(skill-data/native-ui/SKILL.md):视图层——元素、布局、绑定、消息、app 循环;默认路径实现必须与ts-core一起加载。ts-core(skill-data/ts-core/SKILL.md):TypeScript 子集、效果(Cmd)、订阅(Sub)与模块拆分。ts-services(skill-data/ts-services/SKILL.md):当树里有src/services/,或普通 TypeScript 需要Cmd.request背后的文件系统/进程/JSON/regex/Map/Date/class 工作。core --full:当工作触及更低层的运行时接线、WebView、桥接/安全、原生能力、打包或调试时,用native skills get core --full把引用文件一并输出。automation(skill-data/automation/SKILL.md):测试运行中的应用、取快照、请求重载、使用内嵌自动化服务器。zig(skill-data/zig/SKILL.md):仅在既有 Zig 核心、工具链扩展、SDK 实现工作或 Zig 0.16 编译错误时加载(技能按编译错误文本索引,如"no member named 'cwd'"对应std.Io.Dir文件 IO 迁移)。
这套发现机制在 CLI 中实现:native skills list|get <name>命令由 tools/native-sdk/main.zig 派发到 tools/native-sdk/skills.zig,技能源随 CLI 包一起分发(package.json 的files字段包含skill-data与skills)。
自动化:内嵌服务器的确定性驱动
每个 Native SDK 应用(原生渲染与 WebView 外壳皆然)都内嵌自动化服务器,通过基于文件的 IPC(.zig-cache/native-sdk-automation/)工作,面向冒烟测试、带 GUI 会话的 CI 检查与快速运行时检查(automation 技能;实现见 src/automation/)。
典型工作流:
native automate wait # 阻塞直到 ready=true native automate assert 'gpu_nonblank=true' 'role=button name="Reset"' native automate assert --absent 'error event=' native automate list # 窗口摘要 native automate snapshot # 完整快照 native automate screenshot inbox-canvas # 确定性参考渲染 PNG native automate widget-click canvas 3 # 真实指针路径驱动 native automate widget-drag canvas 4 0.25 0.82 # 连续指针控件 native automate widget-wheel canvas 5 18 # 滚动输入 native automate widget-key canvas cmd+c # 修饰键和弦 native automate bridge '{"id":"smoke","command":"native.ping","payload":{"source":"automation"}}'要点:
automate assert优于snapshot | grep链:它轮询(100ms 间隔,--timeout-ms默认 30000),失败输出携带证据(每个未匹配模式 + 快照末尾 20 行),无需 sleep,CI 友好。模式是受限正则子集(字面量、.、后缀*+?、行锚、字符类、\d \w \s),无分组与交替。- 截图走确定性 CPU 参考渲染器:
screenshot <view-label> [scale]把gpu_surface视图的当前画布帧栅格化为.zig-cache/native-sdk-automation/screenshot-<view-label>.png;同一场景的两次捕获字节相同,可支撑黄金图像或“UI 是否变化”检查。注意它只覆盖保留画布视图,不覆盖 WebView 像素。 widget-action ... set_text走与真实输入相同的路径(聚焦、全选、文本输入事件),因此 TEA 应用的on_input镜像收到编辑,模型状态与屏幕一致。- 桥接冒烟测试:请求必须是带
id/command/payload的 JSON;自动化以源zero://inline发送,应用桥接策略必须允许该源否则返回permission_denied。典型native.ping响应为{"id":"smoke","ok":true,"result":{...}}。桥接失败码:unknown_command、permission_denied、handler_failed、payload_too_large、internal_error。 - 文件协议:目录默认相对 CLI 当前工作目录(
native automate要在应用启动目录运行);snapshot.txt头部含ready=true、protocol=<n>、dispatch_errors=<total>、dropped_trace_records=<total>与markup_watch=armed|off;command.txt单槽消费(应用每呈现一帧消费一条命令,CLI 等待并在成功时打印delivered)。 - 开启方式:构建/运行带自动化标志的应用,
zig build run -Dplatform=macos -Dautomation=true;运行器需把native_sdk.automation.Server.init(io, ".zig-cache/native-sdk-automation", "My App")传入RuntimeOptions。未启用自动化的构建会忽略自动化文件。 - 范围说明:自动化不是浏览器 DOM 自动化;WebView DOM 交互不在其列(用前端框架测试或浏览器自动化工具针对 dev server)。
两条替代路径:Zig 核心与 WebView 前端
Zig 核心(--template zig-core)
native init my_app --template zig-core生成src/main.zig。Zig 核心中update看不到std.Io——持久化、记录/关系存储、凭据、子进程、HTTP、时钟与定时器都走类型化效果通道(fx.persist、fx.storeSet、fx.dbQuery、fx.credentialsSet、fx.readFile、fx.spawn、fx.fetch、fx.wallMs、fx.startTimer等)。Zig 0.16 的关键迁移(zig 技能):main(init: std.process.Init)携带进程级分配器、Io、环境与参数;std.fs.cwd()变成std.Io.Dir.cwd()且每个操作紧跟io;容器改为无管理式(.empty初始化 + 每次变更调用传分配器)。由于 Zig 惰性分析,拥有 Zig 代码的应用必须同时跑zig build和zig build test才算改动完成。
WebView 前端(--frontend next|vite|react|svelte|vue)
框架应用把 web 工作留在frontend/,开发时加载本地 dev server、生产时加载打包资源——用native_sdk.frontend.sourceFromEnv(读NATIVE_SDK_FRONTEND_URL,否则服务配置的资源目录)让两种模式共享同一个应用外壳。Vite 通常用http://127.0.0.1:5173/,Next.js 通常用http://127.0.0.1:3000/;应用 WebView 直接加载 dev URL,框架 HMR 仍归框架所有。仓库内的 next 示例、react 示例、svelte 示例、vue 示例 是完整参考。
在仓库中继续深入
- 大型纯 TypeScript + Native markup 参考应用:chatbot 示例(流式 fetch 效果与模块)、soundboard-ts 示例(音频流、滑块 seek、定时器时钟、文本编辑引擎、上下文菜单)、system-monitor-ts 示例(spawn 效果、定时器、表格)。
- 最小底层 WebView 应用:hello 示例;桥接与 WebView 运行时:webview 示例;分层浏览器式示例:browser 示例。
- 窗口化虚拟列表参考:feed 示例(100k 条混合高度确定性语料、触底批处理、零跳滚动风暴测试)。
- 移动宿主嵌入:ios 示例、android 示例。
- 运行时与测试实现:运行时目录(含
canvas_limits.zig预算、effects 测试套件、自动化相关模块)、自动化实现、测试目录。
一句话总结:默认路径(TypeScript 核心 + Native markup +app.json)是学习与交付的起点,Zig 核心与 WebView 前端是显式选择的替代路径,自动化服务器让 Agent 能以确定性方式验证每个改动——这套技能发现系统把上述全部知识按需交付给 Agent。
- 桌面应用
- 跨平台
【免费下载链接】native
Toolkit for building native desktop apps
相关推荐
Native SDK 完全指南:用 TypeScript 与声明式 Markup 构建零运行时原生桌面应用
Native SDK 完全指南:用 TypeScript 与声明式 Markup 构建零运行时原生桌面应用 Native SDK 是一套面向原生桌面应用开发的完
桌面应用跨平台用 TypeScript + Native markup 构建原生桌面音乐应用:soundboard-ts 实战指南
用 TypeScript + Native markup 构建原生桌面音乐应用:soundboard ts 实战指南 本文以 Native SDK 仓库中的 e
桌面应用跨平台Native SDK CLI 使用指南:用 @native-sdk/cli 构建原生桌面应用
Native SDK CLI 使用指南:用 @native sdk/cli 构建原生桌面应用 @native sdk/cli 是 Native SDK(本仓库
桌面应用跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考