生命周期与回调
插件不是「加载一次就一直跑」。它会跟着小程序、页面、开关反复经历注入与卸载。写插件时,生命周期比 API 更容易踩坑。
一张图
text
安装 / 启用
│
├─ 当前小程序 appid 命中 appids 过滤
▼
注入 core + 逻辑层脚本
│
├─ attach { appid, version }
├─ pageChange { route, options, appid }
├─ storageWrite { op, key, value, plugin }
├─ network { url, method, status, ... }
├─ nativeReq / nativeResp { api, appid, seq, body }
│
├─ 停用 / 卸载 / 切小程序 / 关小程序
▼
detach面板是另一条线:每次打开都是新的 iframe,关闭即销毁。
三个上下文,三种生命周期
| 上下文 | 生命周期 | 说明 |
|---|---|---|
| 面板 | 打开 → 关闭 | 每次都是新 iframe,内存状态不保留 |
| 逻辑层 | 跟随 appservice | 小程序运行期间常驻;切小程序重建 |
| 渲染层 | 跟随页面 target | 短连接注入,页面切换会重新注入 |
所以:
- 面板里的
let state关掉就没了,要持久化请用wad.storage; - 逻辑层的状态在小程序关闭后也没了,不要假设它跨会话;
- 渲染层每次页面切换都要重新跑一遍注入逻辑。
attach
js
wad.on('attach', function (d) {
// d = { appid, version }
wad.log('注入到 ' + d.appid + ',插件版本 ' + d.version);
start();
});触发时机:
- 插件第一次注入到当前小程序;
- 插件启用 / 停用后再启用;
- 插件更新(版本号变化);
- 小程序切换(新 appid)。
attach 可能重复触发,初始化要幂等:
js
let timer = null;
function start() {
clearInterval(timer);
timer = setInterval(tick, 1000);
}
wad.on('attach', start);
wad.on('detach', function () {
clearInterval(timer);
timer = null;
});detach
js
wad.on('detach', function () {
// 还原 DOM、清定时器、恢复被包装的 wx API
});触发时机:
- 插件被停用;
- 插件被卸载;
- 小程序关闭;
- 切换到另一个小程序。
不清理会留下脏状态
渲染层改过的 DOM、逻辑层包装过的 wx API、定时器,都不会被宿主自动还原。尤其是「页面文字编辑」这类插件,detach 没写好会继续吞掉用户点击。
pageChange
js
wad.on('pageChange', function (d) {
// d = { route, options, appid }
wad.log('进入页面 ' + d.route);
});页面路由变化时触发。适合:
- 按页面显示不同的浮层;
- 记录用户路径;
- 页面切换后重新打标 DOM。
storageWrite
js
wad.on('storageWrite', function (d) {
// d = { op: 'set' | 'remove' | 'clear', key, value, plugin }
});业务调用 wx.setStorage* / removeStorage* / clearStorage* 时触发。插件自己命名空间的写入不会触发,避免自反馈。
network
js
wad.on('network', function (d) {
// d = { url, method, status, kind, ws, dir, len, id, at }
});首次订阅时宿主会自动打开网络捕获;最后一个订阅者离开时还原。
nativeReq / nativeResp
js
wad.on('nativeReq', function (d) {
// d = { api, appid, seq, body }
var o = JSON.parse(d.body);
o.__probe = 1;
return o;
});请求进入 native 边界前、响应回业务前触发。详见 事件系统。
appids 过滤
插件默认对所有小程序生效。也可以限定范围:
http
POST /v1/plugins/<id>/appids
{ "appids": "wx1234567890abcdef,wxaaaaaaaaaaaaaaaa" }* 表示全部。不在列表里的 appid 不会注入,也就不会收到任何事件。
失败与重试
- 单次注入失败不会拖垮小程序;
- 同一代连续失败 2 次,宿主会停止继续注入;
- 插件配置变化(启用、更新、切小程序)会开启新一代,重新尝试;
- 插件运行时报错只影响自己,不会中断其它插件。
卸载时宿主会做什么
- 停止注入;
- 删除插件目录(脚本、资源、图标等);
- 删除该插件创建的网络规则;
- 关闭属于它的面板;
- 触发一次
detach。
插件的 DOM 修改、wx 包装、定时器仍要自己清。
一份可靠的骨架
html
<script type="text/wad-logic">
var state = { timer: null, wrapped: false };
function boot(appid) {
stop();
state.timer = setInterval(function () {
// 周期性工作
}, 2000);
}
function stop() {
if (state.timer) clearInterval(state.timer);
state.timer = null;
}
wad.on('attach', function (d) { boot(d.appid); });
wad.on('detach', function () { stop(); });
wad.on('pageChange', function (d) { /* 页面级逻辑 */ });
</script>