插件系统总览
插件是 WeAppDev 的扩展方式。它不打包、不签名,一个 HTML 文件就能装进去。
但写法和普通网页不一样:小程序的逻辑层(V8)和渲染层(XWeb)是两个进程,没有统一的 DOM。所以一个插件由三个上下文组成,跨层通信由宿主总线转发。
三个上下文
text
plugin.html
├── 面板 <script> 浮窗 WebView · 有 wad SDK,无 wx
├── 逻辑层 <script type="text/wad-logic"> appservice V8 · 有 wx,无 DOM
└── 渲染层 <script type="text/wad-render"> 当前页面 XWeb · 有 DOM,无 wx| 能力 | 面板 | 逻辑层 | 渲染层 |
|---|---|---|---|
id / name / version / appid | ✅ | ✅ | ✅ |
log / on / emit | ✅ | ✅ | ✅ |
off | ✅ | ✅ | — |
register(name, fn) | — | ✅ | — |
logic.call | Promise | 同步 | Promise(参数是数组) |
logic.eval / page | Promise | 同步 | — |
render.eval | Promise | 投递 | 同步 |
render.dom | — | — | ✅ |
http.* | 宿主代理 | wx.request | — |
storage.* | 异步 | 同步(wx storage) | — |
net.* | 异步 | 同步 records | — |
nativeReq / nativeResp | 订阅 | ✅ 改写 | — |
ui.* | 组件库 + toast | 仅 toast | 仅 toast |
asset | — | ✅ | ✅ |
loadWasm | 原生 WebAssembly | ✅ | ✅ |
loadScript | — | ⚠ 沙箱 | ✅ |
loadCss | — | — | ✅ |
三个 wad 不是同一套
同名方法的同步/异步和参数形式不同。比如渲染层 wad.logic.call('add', [1, 2]) 第二个参数是数组,面板则是 wad.logic.call('add', 1, 2)。写跨上下文代码前先看 核心 API。
一个最小插件
html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="wad:package" content="hello-min">
<meta name="wad:name" content="最小插件">
</head>
<body>
<button onclick="wad.ui.toast('It works!')">点我</button>
<script src="/ui/plugin-sdk.js"></script>
<script>
wad.ready.then(function () {
wad.ui.setTitle('最小插件 · ' + wad.appid);
});
</script>
</body>
</html>三段脚本各跑各的,互不阻塞。宿主会按代注入,切换小程序时重新建立上下文。
能力一览
观察
- 订阅
pageChange,记录路由栈; - 订阅
storageWrite,监控 token 类 key; - 订阅
network,实时拿到 HTTP / WS 摘要; - 订阅
nativeReq/nativeResp,在 JSAPI 进出 native 的边界改写请求与响应; - 读取
net.records,回溯最近 n 条请求与响应体; - 用
wad.asset加载 zip 里的 WASM、外部脚本与样式。
操作
logic.eval在业务上下文里求值;render.dom直接改页面 DOM;net.addRule改包、mock、重定向;logic.call调用自己注册的 Skill。
展示
- 面板浮窗,固定亮色主题;
wad.ui.*组件库,不写 CSS 也有一致外观;- 也可以完全自己写样式,宿主只注入一个基础样式表。
生命周期
text
安装 → 启用 → attach({ appid, version })
├── 面板打开(每次是全新 iframe)
├── 逻辑层脚本注入
└── 渲染层脚本注入
pageChange / storageWrite / network
detach → 停用 / 卸载 / 切小程序面板每次打开都是新的 iframe,内存变量只在当次生命周期内有效。需要持久化的状态请放 wad.storage。
限制
| 项 | 限制 |
|---|---|
| 单文件 HTML | ≤ 2 MB |
text/wad-logic / text/wad-render | 各 ≤ 256 KB |
| 同时启用插件 | ≤ 120 个 |
| 单条总线消息 | ≤ 256 KB |
| RPC 单帧 | ≤ 200 KB |
| RPC 超时 | 6 s |
外部 <script src> | 不执行;需要外部脚本用 wad.loadScript(渲染层) |
| zip 资源 | 总量 ≤ 8 MB,单资产 ≤ 4 MB |
插件依赖调试通道
插件注入走 CDP。调试关闭时零注入,面板仍可打开,但 logic / storage / network 不运行。这是有意的安全边界。
安全性
- 插件运行在独立的 iframe / 上下文里,不能直接访问宿主的 Java 对象;
- 插件存储按
__wad_<pluginId>_前缀命名空间隔离; - 网络规则按 owner 隔离,
rules()只能看到自己的; - 卸载插件会删除插件目录与它创建的网络规则;
- 安装前做语法预检,拒绝无法编译的脚本。
插件仍然可以读写当前小程序的业务数据、修改页面 DOM。只安装你信任的插件。