介绍

了解 UDhold 插件的运行机制、形态分类、能力域与权限模型。

这一章回答三个问题:插件在 UDhold 里是什么、能做成什么形态、能调用哪些能力。读完你就能判断自己的点子适不适合做成插件,该做成哪种形态。

插件是什么

UDhold 宿主基于 Tauri 2 构建。每个插件打开时,宿主会为它创建一个独立的 WebView(网页容器),加载插件声明的前端页面;插件与宿主之间通过注入的 window.udhold 桥对象通信。

┌─────────────── UDhold 宿主(Tauri 2 / Rust)───────────────┐
│  主面板(活动栏 / 左侧面板 / 工作区 / 右侧面板)            │
│  ┌────────────┐  ┌──────────────────┐  ┌────────────┐    │
│  │ 插件 A      │  │ 插件 B(你的插件) │  │ 插件 C      │    │
│  │ WebView     │  │ WebView          │  │ 服务进程    │    │
│  └────────────┘  └────────┬─────────┘  └────────────┘    │
│                           │ window.udhold(桥 + 权限网关) │
│  文件 / 剪贴板 / 数据库 / AI / 系统命令 ……(26 个能力域)   │
└──────────────────────────────────────────────────────────┘

插件工程的唯一契约是根目录的 plugin.json——名字、入口、面板槽位、搜索关键词、权限需求全部声明在这一个文件里,宿主按声明加载与管控。清单体系兼容 uTools 插件协议,熟悉 uTools 开发的开发者可以无缝迁移。

插件的四种形态

形态构成典型例子适合场景
页面插件前端工程(Vue / React / 纯 HTML),构建出静态产物计算器、JSON Tools、待办清单有界面的工具
免构建静态插件一个 index.html + plugin.json,无需 Node 工程简单的小工具页轻量工具、快速验证想法
纯服务插件只有 services[] 声明(Node / Python / exe),没有界面后台服务、绿色软件封装无界面的后台能力
页面 + 服务前端页面 + 声明式服务进程需要本地后端的复杂插件本地数据库、爬虫、编译类工具

页面插件还可以通过 pluginSetting 进一步定制形态:嵌入工作区面板、挂在左右侧栏、打开即分离成独立窗口(Detach)、进活动栏顶部/底部菜单(Menu / MenuBottom)等,详见快速上手的清单字段说明。

能调用哪些能力

插件通过 window.udhold 调用宿主能力,共 26 个命名空间、200 多个方法。常用的能力域:

能力域说明示例调用
db / dbStorage / dbCryptoStorage文档数据库 / 键值存储 / 加密键值存储,数据自动按插件隔离udhold.dbStorage.setItem('k', 'v')
plugin / router / route插件运行时:生命周期钩子、跨插件调用、tab 操作udhold.router.push('files')
files文件资源管理:列举、新建、重命名、删除、批量复制、监听udhold.files.list('D:\\')
clipboard剪贴板历史与读写udhold.copyText('文本')
ai / ai.models大模型推理(流式)、模型配置udhold.ai({ model, messages })
system / shell系统命令、通知、打开文件/网址udhold.shellOpenExternal(url)
search唤起全局搜索框udhold.search.openWithKeyword('kw')
setting宿主外观与行为配置udhold.setting.setTheme('dark')
udbrowser内嵌浏览器自动化(打开页面、点击、取数)udhold.udbrowser.create()
service / node拉起并管理本地服务进程udhold.service.spawn(cfg)
user / sync / netdisk登录态、WebDAV 同步、简盘udhold.user.isLogin()

除了直接调用,插件还能通过 exports + registerTool 对外暴露接口供其他插件(以及宿主的 MCP 服务)调用,形成插件间的协作生态。

权限模型

UDhold 采用三层声明式权限:用到什么,就在 plugin.json 里声明什么,未声明的调用会被宿主权限网关拒绝(返回 PERMISSION_DENIED)。

声明字段管什么示例
permissions[]平台能力路径:敏感域(文件、剪贴板历史、AI、登录态等)必须声明;存储、路由等基础能力免声明"permissions": ["files.list", "ai.*"]
tauri[]原生能力:对话框、通知、文件选择器等"tauri": ["dialog:default"]
plugins[]跨插件调用白名单:要 push / invoke 其他插件,先在这里登记目标插件名"plugins": ["files"]

通配符只支持后缀:user.* 放行整个 user 域,ai.models.list 精确到单个方法。不要声明 "*"(全量授权,市场审核时视为最高风险)。

生命周期

插件实例有 12 个生命周期钩子,覆盖从打开到销毁的完整过程:

udhold.plugin.onMounted((action) => {})     // 页面就绪,action.code 区分被哪个 feature 唤起
udhold.plugin.onActivated((p) => {})        // tab 切入
udhold.plugin.onDeactivated((p) => {})      // tab 被切走
udhold.plugin.onDetached((p) => {})         // 分离成独立窗口
udhold.plugin.onAttached((p) => {})         // 从独立窗口回归面板
udhold.plugin.onBeforeUnmount((p) => {})    // 实例销毁前(唯一清理时机,宿主等 200ms)
udhold.plugin.onShow((p) => {})             // 获得焦点
udhold.plugin.onBlur((p) => {})             // 失去焦点
udhold.plugin.onMinimized((p) => {})        // 承载窗口最小化
udhold.plugin.onRestored((p) => {})         // 承载窗口还原
udhold.plugin.onAppLaunched((p) => {})      // 宿主启动(粘性)
udhold.plugin.onAppBeforeQuit(() => {})     // 宿主退出前

所有钩子返回取消函数,可多次注册叠加。onMounted 的 action.from 能区分唤起来源(主输入框 main、面板 panel、快捷键 hotkey、其他插件跳转 redirect 等)。

分发方式

  • 插件市场:在「插件开发者」里一键打包上传,审核通过后全平台用户可搜可装;已装用户打开插件时宿主自动检查更新。
  • 本地安装包:打包为 .zip,可以发给朋友双击安装,或在插件中心手动安装,适合内部分发与灰度测试。

开发前的准备

需要说明
UDhold 桌面端调试与打包都在宿主里完成,下载安装
HTML / CSS / JavaScript 基础插件本质是 Web 页面;推荐用 Vue 3(官方插件与组件库同栈,生态最顺)
Node.js 20+ 与 pnpm工程型插件需要;纯静态插件可跳过
一个想法从自己每天会重复做的小事开始,最容易做出好插件

准备好了?进入快速上手,20 分钟跑起你的第一个插件。