news 2026/10/8 17:56:37

Baguette插件开发完全指南:清单文件、能力权限与Bakery分发机制详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Baguette插件开发完全指南:清单文件、能力权限与Bakery分发机制详解

Baguette插件开发完全指南:清单文件、能力权限与Bakery分发机制详解

【免费下载链接】baguetteHeadless control for Apple's Simulators — 3D models, taps, swipes, multi-finger gestures, 60 fps streaming, and a multi-device farm项目地址: https://gitcode.com/gh_mirrors/baguette/baguette

想给你的 iOS 模拟器工作流加上自定义面板吗?本文带你从零掌握Baguette 插件开发的全部要点——插件清单文件baguette-plugin.json的写法、能力权限令牌(capabilities + 逐次调用 token)的安全模型,以及Bakery 分发机制(用baguette.json菜单把插件发布成可信任的 git 仓库)。Baguette 是一款无头(headless)控制 Apple iOS 模拟器的 Swift CLI + Web UI 工具,支持 60fps 屏幕流、点按/滑动/多指手势、多设备农场,而插件系统正是它"不碰核心就能扩展"的方式。

插件的本质:一个目录 + 一份清单 + 一个由 Baguette 以子进程方式运行的命令。它自带的任何代码都不会被加载进 Baguette 进程或页面里——它只声明面板,Baguette 用宿主自己的标记把它画出来。

一分钟理解插件模型

把插件想象成"面包"(baguette 即法棍 🥖),而Bakery(面包房)就是存放面包的 git 仓库:

概念对应物作用
插件(Plugin)baguette-plugin.json所在目录声明贡献的面板/命令 + 声明所需权限
命令(Command)run字段指向的脚本Baguette 以子进程运行,stdout 输出一个 JSON
面包房(Bakery)根目录带baguette.json的 git 仓库你信任一次的来源,之后可安装它提供的任意插件
权限令牌(Token)每次命令调用独立签发只携带该插件声明的能力,命令一结束即吊销

两个关键安全事实:

  1. 插件命令是真实进程,以你的权限运行——和你brew install任何东西的信任程度相同;
  2. 安装插件永远不会执行它的代码——安装只做 clone 和复制文件,没有任何 postinstall 钩子;代码只在你激活插件时(点击侧栏按钮或baguette plugin run)才运行。

官方完整示例见examples/expo-bakery/,它包含两个只声明input能力的小插件(⌘R 重载、⌘D 开发者菜单)。

插件清单文件:baguette-plugin.json 逐字段讲解

一个插件就是一个包含 baguette-plugin.json 的目录。以官方deeplink插件为例:

{ "name": "deeplink", "version": "1.2.0", "apiVersion": 1, "description": "Open deep links on the focused simulator…", "icon": "link", "capabilities": ["open-url"], "contributes": { "commands": [ { "id": "open", "title": "Open a deep link", "run": ["/usr/bin/python3", "bin/open.py"] } ], "panels": [ { "id": "open", "title": "Deep Links", "icon": "link", "when": "simulator.booted", "body": { "kind": "list", "source": "open", "rowAction": "fill", "prompt": { "arg": "url", "placeholder": "myapp://path", "submit": "Open", "filter": true, "complete": true, "history": true } } } ] } }

关键字段速查

字段说明
name/version插件名与语义化版本;命令按插件命名空间隔离(deeplink:open),两个插件都可以各自提供reload
apiVersion契约版本;Baguette 遇到更新的版本会直接拒绝,而不是猜。省略时永久等于 1
icon从 Baguette 内置图标表中选一个(accessibility、reload、link、wrench…);未知名字会画成puzzle而不是让插件失败——清单是不可信文本,绝不渲染任意标记
capabilities强制执行的权限声明,见下一节
contributes.commands[].runargv,相对插件自身目录解析;建议写绝对解释器路径(如/usr/bin/python3)
contributes.panels[].whensimulator.booted(模拟器已开机才显示)或省略表示"总是显示"
body.kind/rowAction目前唯一控件是list;行点击行为可为highlight/tap/copy/run/fill

命令契约:收到什么、输出什么

面板打开时,Baguette 运行其source命令,并通过环境变量(同样内容也在 stdin JSON 中)注入上下文:

环境变量含义
BAGUETTE_URL正在运行的服务地址——去调它,别重新起baguette进程(省约 1.2 秒框架解析)
BAGUETTE_UDID当前聚焦的设备(无聚焦时缺失)
BAGUETTE_TOKEN会话令牌,作为X-Baguette-Token头调用插件 API

命令只需在 stdout 打印一个 JSON 对象并退出:

{ "ok": true, "rows": [ { "title": "Button has no label", "subtitle": "AXButton", "severity": "error", "frame": { "x": 24, "y": 380, "width": 44, "height": 44 } } ] }

注意:frame是扁平的设备点坐标(与手势坐标同一空间,rowAction: "tap"直接点其中心);输出非 JSON 是错误而非"空结果"——空白面板会被误读为"全部通过"。另外,命令只有 10 秒预算:到期收到SIGTERM,再 2 秒后SIGKILL。

发布前务必先自检:

baguette plugin validate path/to/plugin

能力权限令牌:声明即边界

capabilities不是注释,是在每个路由前面强制执行的封闭集合:

能力授予的访问
describe-ui读取屏幕的可访问性树
input发送手势、按键、硬件按钮
screenshot/logs截图 / 实时统一日志(WebSocket)
interface外观、对比度、文本大小
status-bar状态栏覆盖
location模拟 GPS
apps/media安装 App / 添加照片视频(刻意分开:装测试图不该被信任装软件)
open-url打开深链接、列已注册 schemes
simulators列出模拟器

令牌的生命周期:一次调用,一枚令牌

  • 每次命令调用都会拿到自己的令牌,恰好携带该插件声明的能力集合(实现见 PluginDispatch.swift 与 PluginGrants.swift);
  • 命令一结束,令牌立即吊销——无论以何种方式结束,活过父请求的子进程没有凭据;
  • 越权调用即使令牌本身有效也回答403:"this plugin did not declare theinputcapability";
  • 默认最小权限:什么都不声明 = 什么都不能做;未知能力名是解析错误,让你在validate阶段就发现拼写错误;
  • 表中没有的路由(开机、相机源、安装其他插件等)任何能力都够不着——以后新增的路由也默认对插件关闭,漂移方向永远朝权限更少的方向。

设计文档 design.md 解释得透彻:共享会话密钥做不到这一点,因为服务器无法分辨"谁在调用"。同时请记住——能力令牌管的是插件 API 边界,不是进程沙箱:真正的同意发生在你信任 Bakery 的那一刻。

面板三种玩法:报告、可输入、可开关

除了普通行,Baguette 的宿主侧面板还支持两种"追加式"能力(不提升apiVersion,老版本会优雅降级为普通列表):

  • body.prompt(可输入的面板):列表上方加一个文本框,filter就地过滤已返回的行、complete灰色补全 + Tab 接受、history记忆提交记录。这正是deeplink插件的体验:点account://会把该 scheme 填进输入框待你补全路径,而不是打开一个没人想要的裸 scheme。
  • body.control(可开关的面板):行声明state/value/group,清单声明控件外观(switch/checkbox/radio)。勾选不花子进程——面板累积勾选、按下提交按钮才一次性发送(永远是数组);未确认的行会被宿主画成pending状态,设备拒绝的设置会"弹回真相"。
  • rowAction: "run":把控制权交还插件——点"Dark"会带args再次调用同一命令,面板用设备真实回报重渲染,所见即所得。

Bakery 分发机制:把你的插件装进别人的工具箱

一个Bakery就是任何提供插件的 git 仓库——在它根目录放一个baguette.json"菜单"即可(必须是仓库顶层,不能放子目录):

{ "name": "tddworks/expo-tools", "description": "Expo / React Native helpers", "plugins": [ { "name": "expo-reload", "path": "plugins/expo-reload" }, { "name": "expo-devmenu", "path": "plugins/expo-devmenu" } ] }

完整示例见 baguette.json 与 expo-bakery/README.md。结构一目了然:两个文件,两种职责——baguette.json是面包房的菜单,每个插件的baguette-plugin.json是它自己的清单。

信任与安装:一行命令

baguette bakery add <owner>/<repo> # 信任一个来源(只需一次) baguette plugin show <name> # 安装前先看它能做什么 baguette plugin install <name> # 或:plugin install owner/repo/name

信任是按面包房、一次性的,而且"pin(固定 commit)是需求,不是备注":添加面包房时记录你看到的 commit,之后每次安装都按名字取那个 commit,而不是默认分支今天指向的 HEAD。如果固定 commit 已不可用(force-push、重写历史),安装会失败而不是悄悄回退——想前进就显式运行bakery update。

日常维护:

baguette bakery outdated # 逐个询问远端是否已前进(只报告,不改动) baguette plugin update # 在最新 commit 重新拉取并重装

本地开发则完全不用安装——baguette serve --plugin-dir ./my-plugins让侧栏直接拾取,同名插件会遮蔽已安装版本;发布前用baguette plugin validate体检。

浏览器的边界:可以装,不能信

在 focus mode 里,插件侧栏底部的+按钮可以安装你已信任面包房里的插件(与plugin install完全等价);但信任新来源始终是终端行为——弹窗按钮不算真正的同意。设计上的考量见 design.md:安装路由只能用bakeries.json里已记录的身份寻址,即使来源校验出错,爆炸半径也只是"从你已审查过的仓库装一个插件"。

发布前检查清单 📋

  1. ☐ 插件目录含合法baguette-plugin.json,baguette plugin validate无告警
  2. ☐capabilities只声明最少必需的权限(apps和media分开学)
  3. ☐ 命令只打印一个 JSON 对象;失败时输出{"ok":false,"message":"…"}
  4. ☐ 命令在 10 秒内完成,清理逻辑从速
  5. ☐ 调BAGUETTE_URL而非重起 CLI 子进程
  6. ☐ 仓库根目录放好baguette.json菜单,path保持在仓库内
  7. ☐ 让用户先bakery add信任、plugin show预览,再plugin install

从examples/expo-bakery/复制起步,加上 authoring.md 的字段细节与 README.md 的 HTTP 路由表,你的第一个 Baguette 插件今天就能装进别人的工具栏。Bon appétit 🥖

【免费下载链接】baguetteHeadless control for Apple's Simulators — 3D models, taps, swipes, multi-finger gestures, 60 fps streaming, and a multi-device farm项目地址: https://gitcode.com/gh_mirrors/baguette/baguette

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 17:55:46

Nature Food|生科院蒋建东教授团队揭示植物有益细菌的全球分布格局及未来变化:用TaoToken统一Key复现菌群分布数据检索流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 17:54:04

外文文献读得慢?科迅捷AI帮你高效读完一篇英文论文

写论文绕不开外文文献&#xff0c;可很多同学一看到英文论文就头疼&#xff1a;逐句翻译太慢&#xff0c;跳着读又怕漏掉重点&#xff0c;一篇文献读下来一两个小时&#xff0c;还没记住多少。今天这篇&#xff0c;分享一套读外文文献的高效方法&#xff0c;让你半小时吃透一篇…

作者头像 李华