@jhh96/light-app-bridge 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/lightAppBridge.d.ts +14 -4
- package/dist/lightAppBridge.js +56 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,16 +15,15 @@
|
|
|
15
15
|
| `window.worklink`(含 `invokeModuleMethodSync`) | 发送消息 / 取 webContentsId | preload 注入 |
|
|
16
16
|
| `window.worklink.plugin.getContentContext` | 解析目标轻应用 webContentsId(**仅 plugin 角色**) | pluginLightAppPreload 注入 |
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
**收消息(自动选择,不强依赖 waltz):**
|
|
19
19
|
|
|
20
20
|
| 监听后端 | 优先级 | 适用环境 | 说明 |
|
|
21
21
|
|---------|--------|---------|------|
|
|
22
22
|
| `window.waltz.event.on('native-call-js')` | 高(优先) | 有 waltz 注入的环境 | 推荐路径,立即可用 |
|
|
23
|
-
| `window.handleMessageFromNative` | 低(回退) | 无 waltz 的环境 |
|
|
23
|
+
| `window.handleMessageFromNative` | 低(回退) | 无 waltz 的环境 | 由 SDK 定义此全局方法(该方法原本由 waltz.min.js 注册;无 waltz 时为 undefined,renderer 投递消息前会检查其类型,没人定义则消息被丢弃)。renderer 收到消息后主动调用它传入消息。若该方法已存在则包装透传,不破坏原逻辑 |
|
|
24
24
|
|
|
25
|
-
- 两者都始终不可用时,`connect()`/`ready()` reject(构造不抛,因监听后端允许稍后出现)
|
|
26
25
|
- SDK 内部按 waltz → handleMessageFromNative 顺序探测,无需手动指定
|
|
27
|
-
-
|
|
26
|
+
- 握手会等监听绑定后才开始,避免早到的 ack/hello 丢失
|
|
28
27
|
|
|
29
28
|
## 安装(两个项目)
|
|
30
29
|
|
|
@@ -59,14 +58,21 @@ bridge.onMessage((data, id) => {
|
|
|
59
58
|
|
|
60
59
|
```js
|
|
61
60
|
{
|
|
62
|
-
__sdk: '
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
__sdk: 'LightAppBridge', // SDK 标识:过滤出本 SDK 的消息,隔离其它消息
|
|
62
|
+
v: 1, // 协议版本号
|
|
63
|
+
id: 'r_xxx', // 关联 id:send 生成,回复原样带回
|
|
64
|
+
type: 'hello'|'ack'|'req'|'res', // 握手 hello/ack;业务 req/res
|
|
65
|
+
data: any // 任意业务数据
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
## 连接与生命周期
|
|
70
|
+
|
|
71
|
+
- 构造即自动握手(插件发 hello 每秒重试;轻应用持续等待、不超时)
|
|
72
|
+
- 握手失败后**再次 `connect()` 可重连**(自动重置状态,无需重建实例)
|
|
73
|
+
- `destroy()` 销毁实例:解绑监听、拒绝未完成请求;销毁后 `send`/`connect` 立即 reject
|
|
74
|
+
|
|
69
75
|
## 文件
|
|
70
76
|
|
|
71
|
-
- `src/lightAppBridge.
|
|
72
|
-
- `src/index.
|
|
77
|
+
- `src/lightAppBridge.ts` —— SDK 源码(TypeScript,构建产物为 ESM)
|
|
78
|
+
- `src/index.ts` —— barrel re-export
|
package/dist/lightAppBridge.d.ts
CHANGED
|
@@ -70,6 +70,8 @@ export default class LightAppBridge {
|
|
|
70
70
|
private _connectPromise;
|
|
71
71
|
private _unlisten;
|
|
72
72
|
private _listenerReady;
|
|
73
|
+
private _connectFailed;
|
|
74
|
+
private _destroyed;
|
|
73
75
|
/**
|
|
74
76
|
* @param role 角色,省略时按 window.worklink.plugin 是否存在自动探测
|
|
75
77
|
* @param options 超时配置
|
|
@@ -85,13 +87,21 @@ export default class LightAppBridge {
|
|
|
85
87
|
/** 处理一条归一化后的消息 */
|
|
86
88
|
private _onMessage;
|
|
87
89
|
/**
|
|
88
|
-
*
|
|
90
|
+
* 建立连接(握手)。构造时已自动调用,通常无需手动调。
|
|
91
|
+
* - 已连接 / 握手进行中:幂等,返回同一个 Promise
|
|
92
|
+
* - 上次握手失败:重新发起(内部自动重置状态,无需重建实例——
|
|
93
|
+
* 典型场景:插件先启动、轻应用窗口尚未打开导致超时,对端就绪后再次 connect 即可)
|
|
94
|
+
* - 实例已销毁:reject
|
|
95
|
+
* 行为:
|
|
89
96
|
* - 插件:发起握手(解析目标 id → 发 hello → 每秒重试直到收到 ack 或超时)
|
|
90
|
-
* - 轻应用:被动等待 hello
|
|
91
|
-
* 多次调用幂等,返回同一个连接 Promise。
|
|
97
|
+
* - 轻应用:被动等待 hello(持续监听,不超时)
|
|
92
98
|
* @returns 对端 webContentsId
|
|
93
99
|
*/
|
|
94
100
|
connect(): Promise<number | null>;
|
|
101
|
+
/** 重置连接状态(用于首次握手或失败后重连) */
|
|
102
|
+
private _resetConnectState;
|
|
103
|
+
/** 连接失败:标记失败并 reject(再次 connect 可重试) */
|
|
104
|
+
private _failConnect;
|
|
95
105
|
/** 发送 hello(携带自身 webContentsId) */
|
|
96
106
|
private _sendHello;
|
|
97
107
|
/** 收到 hello(轻应用侧):记录对端、回 ack、完成握手 */
|
|
@@ -132,7 +142,7 @@ export default class LightAppBridge {
|
|
|
132
142
|
* @returns 调用以取消监听
|
|
133
143
|
*/
|
|
134
144
|
onMessage(handler: MessageHandler): () => void;
|
|
135
|
-
/**
|
|
145
|
+
/** 销毁实例:解绑消息监听、清空待处理请求、停止握手重试。销毁后实例不可再用 */
|
|
136
146
|
destroy(): void;
|
|
137
147
|
}
|
|
138
148
|
/**
|
package/dist/lightAppBridge.js
CHANGED
|
@@ -163,6 +163,8 @@ export default class LightAppBridge {
|
|
|
163
163
|
this._started = false;
|
|
164
164
|
this._unlisten = null;
|
|
165
165
|
this._listenerReady = null;
|
|
166
|
+
this._connectFailed = false;
|
|
167
|
+
this._destroyed = false;
|
|
166
168
|
let r = role === 'plugin' || role === 'lightapp' ? role : 'lightapp';
|
|
167
169
|
if (role !== 'plugin' && role !== 'lightapp') {
|
|
168
170
|
const wl = window.worklink;
|
|
@@ -204,7 +206,7 @@ export default class LightAppBridge {
|
|
|
204
206
|
})
|
|
205
207
|
.catch((e) => {
|
|
206
208
|
// 理论上不会发生(无 waltz 时必走定义路径),保险起见让连接失败并给出原因
|
|
207
|
-
this.
|
|
209
|
+
this._failConnect(new Error('LightAppBridge 监听后端绑定失败 (' +
|
|
208
210
|
(e && e.message ? e.message : String(e)) + ')'));
|
|
209
211
|
});
|
|
210
212
|
}
|
|
@@ -236,16 +238,27 @@ export default class LightAppBridge {
|
|
|
236
238
|
}
|
|
237
239
|
// —— 连接 / 握手 —— //
|
|
238
240
|
/**
|
|
239
|
-
*
|
|
241
|
+
* 建立连接(握手)。构造时已自动调用,通常无需手动调。
|
|
242
|
+
* - 已连接 / 握手进行中:幂等,返回同一个 Promise
|
|
243
|
+
* - 上次握手失败:重新发起(内部自动重置状态,无需重建实例——
|
|
244
|
+
* 典型场景:插件先启动、轻应用窗口尚未打开导致超时,对端就绪后再次 connect 即可)
|
|
245
|
+
* - 实例已销毁:reject
|
|
246
|
+
* 行为:
|
|
240
247
|
* - 插件:发起握手(解析目标 id → 发 hello → 每秒重试直到收到 ack 或超时)
|
|
241
|
-
* - 轻应用:被动等待 hello
|
|
242
|
-
* 多次调用幂等,返回同一个连接 Promise。
|
|
248
|
+
* - 轻应用:被动等待 hello(持续监听,不超时)
|
|
243
249
|
* @returns 对端 webContentsId
|
|
244
250
|
*/
|
|
245
251
|
connect() {
|
|
246
252
|
var _a;
|
|
247
|
-
if (this.
|
|
253
|
+
if (this._destroyed) {
|
|
254
|
+
return Promise.reject(new Error('实例已销毁,请重建实例'));
|
|
255
|
+
}
|
|
256
|
+
if (this._connected)
|
|
257
|
+
return this._connectPromise;
|
|
258
|
+
if (this._connectStarted && !this._connectFailed)
|
|
248
259
|
return this._connectPromise;
|
|
260
|
+
// 首次调用,或上次握手失败:重置连接状态重新发起
|
|
261
|
+
this._resetConnectState();
|
|
249
262
|
this._connectStarted = true;
|
|
250
263
|
// 等监听后端绑定完成后再握手,避免对端的 ack/hello 在监听绑定前到达而丢失
|
|
251
264
|
const listenerReady = (_a = this._listenerReady) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
@@ -254,7 +267,7 @@ export default class LightAppBridge {
|
|
|
254
267
|
if (this.role === 'plugin') {
|
|
255
268
|
this._handshakeTimer = setTimeout(() => {
|
|
256
269
|
if (!this._connected) {
|
|
257
|
-
this.
|
|
270
|
+
this._failConnect(new Error(`握手超时 (${this.handshakeTimeout}ms),对端未响应`));
|
|
258
271
|
this._clearHelloTimer();
|
|
259
272
|
}
|
|
260
273
|
}, this.handshakeTimeout);
|
|
@@ -280,9 +293,31 @@ export default class LightAppBridge {
|
|
|
280
293
|
}
|
|
281
294
|
// lightapp 被动等待 hello(listener 已绑定),收到后在 _onHello 中回 ack 并 resolve
|
|
282
295
|
})
|
|
283
|
-
.catch((e) => this.
|
|
296
|
+
.catch((e) => this._failConnect(e));
|
|
284
297
|
return this._connectPromise;
|
|
285
298
|
}
|
|
299
|
+
/** 重置连接状态(用于首次握手或失败后重连) */
|
|
300
|
+
_resetConnectState() {
|
|
301
|
+
this._connectDeferred = deferred();
|
|
302
|
+
this._connectPromise = this._connectDeferred.promise.then((peerId) => {
|
|
303
|
+
this._onConnected(peerId);
|
|
304
|
+
return peerId;
|
|
305
|
+
});
|
|
306
|
+
this._connectFailed = false;
|
|
307
|
+
this._connectStarted = false;
|
|
308
|
+
this._clearHelloTimer();
|
|
309
|
+
if (this._handshakeTimer) {
|
|
310
|
+
clearTimeout(this._handshakeTimer);
|
|
311
|
+
this._handshakeTimer = null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/** 连接失败:标记失败并 reject(再次 connect 可重试) */
|
|
315
|
+
_failConnect(e) {
|
|
316
|
+
if (this._destroyed)
|
|
317
|
+
return;
|
|
318
|
+
this._connectFailed = true;
|
|
319
|
+
this._connectDeferred.reject(e instanceof Error ? e : new Error(String(e)));
|
|
320
|
+
}
|
|
286
321
|
/** 发送 hello(携带自身 webContentsId) */
|
|
287
322
|
_sendHello() {
|
|
288
323
|
if (this._target == null)
|
|
@@ -291,16 +326,18 @@ export default class LightAppBridge {
|
|
|
291
326
|
}
|
|
292
327
|
/** 收到 hello(轻应用侧):记录对端、回 ack、完成握手 */
|
|
293
328
|
_onHello(fromId) {
|
|
294
|
-
if (fromId
|
|
295
|
-
|
|
329
|
+
if (fromId == null)
|
|
330
|
+
return; // 无法定位对端则忽略(真实环境该字段恒有值),握手不完成
|
|
331
|
+
this._recordPeer(fromId);
|
|
296
332
|
// 回 ack,携带自身 webContentsId
|
|
297
|
-
|
|
298
|
-
this._send(fromId, this._envelope('ack', { from: this.getId() }));
|
|
333
|
+
this._send(fromId, this._envelope('ack', { from: this.getId() }));
|
|
299
334
|
// 握手完成(resolve 幂等,重复 hello 只回 ack)
|
|
300
335
|
this._connectDeferred.resolve(fromId);
|
|
301
336
|
}
|
|
302
337
|
/** 收到 ack(插件侧):确认连接 */
|
|
303
338
|
_onAck(fromId) {
|
|
339
|
+
if (fromId == null)
|
|
340
|
+
return; // 无法定位对端则忽略
|
|
304
341
|
this._recordPeer(fromId);
|
|
305
342
|
this._connectDeferred.resolve(fromId);
|
|
306
343
|
}
|
|
@@ -402,6 +439,8 @@ export default class LightAppBridge {
|
|
|
402
439
|
* @returns 对端回调返回的数据
|
|
403
440
|
*/
|
|
404
441
|
send(data, options = {}) {
|
|
442
|
+
if (this._destroyed)
|
|
443
|
+
return Promise.reject(new Error('实例已销毁'));
|
|
405
444
|
const timeout = options.timeout != null ? options.timeout : this.timeout;
|
|
406
445
|
return this.ready().then((targetId) => {
|
|
407
446
|
const id = genId();
|
|
@@ -437,8 +476,11 @@ export default class LightAppBridge {
|
|
|
437
476
|
this._messageHandlers.splice(i, 1);
|
|
438
477
|
};
|
|
439
478
|
}
|
|
440
|
-
/**
|
|
479
|
+
/** 销毁实例:解绑消息监听、清空待处理请求、停止握手重试。销毁后实例不可再用 */
|
|
441
480
|
destroy() {
|
|
481
|
+
if (this._destroyed)
|
|
482
|
+
return;
|
|
483
|
+
this._destroyed = true;
|
|
442
484
|
if (this._unlisten) {
|
|
443
485
|
try {
|
|
444
486
|
this._unlisten();
|
|
@@ -451,6 +493,8 @@ export default class LightAppBridge {
|
|
|
451
493
|
clearTimeout(this._handshakeTimer);
|
|
452
494
|
this._handshakeTimer = null;
|
|
453
495
|
}
|
|
496
|
+
// 进行中的握手直接失败(已 resolve 的话 reject 是 no-op)
|
|
497
|
+
this._connectDeferred.reject(new Error('实例已销毁'));
|
|
454
498
|
// 拒绝所有未完成的请求
|
|
455
499
|
this._pending.forEach((p) => {
|
|
456
500
|
clearTimeout(p.timer);
|