@jhh96/light-app-bridge 1.0.4 → 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 +16 -6
- package/dist/lightAppBridge.js +66 -19
- 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
|
@@ -37,7 +37,7 @@ export interface Envelope {
|
|
|
37
37
|
export interface BridgeOptions {
|
|
38
38
|
/** send 默认超时(ms),默认 3000 */
|
|
39
39
|
timeout?: number;
|
|
40
|
-
/** 握手超时(ms),默认 30000 */
|
|
40
|
+
/** 握手超时(ms),默认 30000。仅 plugin 角色生效;lightapp 端持续等待,不超时 */
|
|
41
41
|
handshakeTimeout?: number;
|
|
42
42
|
}
|
|
43
43
|
/** send 单次调用选项 */
|
|
@@ -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
|
-
*
|
|
89
|
-
* -
|
|
90
|
-
* -
|
|
91
|
-
*
|
|
90
|
+
* 建立连接(握手)。构造时已自动调用,通常无需手动调。
|
|
91
|
+
* - 已连接 / 握手进行中:幂等,返回同一个 Promise
|
|
92
|
+
* - 上次握手失败:重新发起(内部自动重置状态,无需重建实例——
|
|
93
|
+
* 典型场景:插件先启动、轻应用窗口尚未打开导致超时,对端就绪后再次 connect 即可)
|
|
94
|
+
* - 实例已销毁:reject
|
|
95
|
+
* 行为:
|
|
96
|
+
* - 插件:发起握手(解析目标 id → 发 hello → 每秒重试直到收到 ack 或超时)
|
|
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,26 +238,40 @@ export default class LightAppBridge {
|
|
|
236
238
|
}
|
|
237
239
|
// —— 连接 / 握手 —— //
|
|
238
240
|
/**
|
|
239
|
-
*
|
|
240
|
-
* -
|
|
241
|
-
* -
|
|
242
|
-
*
|
|
241
|
+
* 建立连接(握手)。构造时已自动调用,通常无需手动调。
|
|
242
|
+
* - 已连接 / 握手进行中:幂等,返回同一个 Promise
|
|
243
|
+
* - 上次握手失败:重新发起(内部自动重置状态,无需重建实例——
|
|
244
|
+
* 典型场景:插件先启动、轻应用窗口尚未打开导致超时,对端就绪后再次 connect 即可)
|
|
245
|
+
* - 实例已销毁:reject
|
|
246
|
+
* 行为:
|
|
247
|
+
* - 插件:发起握手(解析目标 id → 发 hello → 每秒重试直到收到 ack 或超时)
|
|
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();
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
this.
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
// 握手超时保护:仅插件(主动方)需要——它发了 hello 却收不到 ack 说明对端异常。
|
|
266
|
+
// 轻应用(被动方)持续等待,不超时:插件可能任意晚才发起连接。
|
|
267
|
+
if (this.role === 'plugin') {
|
|
268
|
+
this._handshakeTimer = setTimeout(() => {
|
|
269
|
+
if (!this._connected) {
|
|
270
|
+
this._failConnect(new Error(`握手超时 (${this.handshakeTimeout}ms),对端未响应`));
|
|
271
|
+
this._clearHelloTimer();
|
|
272
|
+
}
|
|
273
|
+
}, this.handshakeTimeout);
|
|
274
|
+
}
|
|
259
275
|
listenerReady
|
|
260
276
|
.then(() => {
|
|
261
277
|
if (this._connected)
|
|
@@ -277,9 +293,31 @@ export default class LightAppBridge {
|
|
|
277
293
|
}
|
|
278
294
|
// lightapp 被动等待 hello(listener 已绑定),收到后在 _onHello 中回 ack 并 resolve
|
|
279
295
|
})
|
|
280
|
-
.catch((e) => this.
|
|
296
|
+
.catch((e) => this._failConnect(e));
|
|
281
297
|
return this._connectPromise;
|
|
282
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
|
+
}
|
|
283
321
|
/** 发送 hello(携带自身 webContentsId) */
|
|
284
322
|
_sendHello() {
|
|
285
323
|
if (this._target == null)
|
|
@@ -288,16 +326,18 @@ export default class LightAppBridge {
|
|
|
288
326
|
}
|
|
289
327
|
/** 收到 hello(轻应用侧):记录对端、回 ack、完成握手 */
|
|
290
328
|
_onHello(fromId) {
|
|
291
|
-
if (fromId
|
|
292
|
-
|
|
329
|
+
if (fromId == null)
|
|
330
|
+
return; // 无法定位对端则忽略(真实环境该字段恒有值),握手不完成
|
|
331
|
+
this._recordPeer(fromId);
|
|
293
332
|
// 回 ack,携带自身 webContentsId
|
|
294
|
-
|
|
295
|
-
this._send(fromId, this._envelope('ack', { from: this.getId() }));
|
|
333
|
+
this._send(fromId, this._envelope('ack', { from: this.getId() }));
|
|
296
334
|
// 握手完成(resolve 幂等,重复 hello 只回 ack)
|
|
297
335
|
this._connectDeferred.resolve(fromId);
|
|
298
336
|
}
|
|
299
337
|
/** 收到 ack(插件侧):确认连接 */
|
|
300
338
|
_onAck(fromId) {
|
|
339
|
+
if (fromId == null)
|
|
340
|
+
return; // 无法定位对端则忽略
|
|
301
341
|
this._recordPeer(fromId);
|
|
302
342
|
this._connectDeferred.resolve(fromId);
|
|
303
343
|
}
|
|
@@ -399,6 +439,8 @@ export default class LightAppBridge {
|
|
|
399
439
|
* @returns 对端回调返回的数据
|
|
400
440
|
*/
|
|
401
441
|
send(data, options = {}) {
|
|
442
|
+
if (this._destroyed)
|
|
443
|
+
return Promise.reject(new Error('实例已销毁'));
|
|
402
444
|
const timeout = options.timeout != null ? options.timeout : this.timeout;
|
|
403
445
|
return this.ready().then((targetId) => {
|
|
404
446
|
const id = genId();
|
|
@@ -434,8 +476,11 @@ export default class LightAppBridge {
|
|
|
434
476
|
this._messageHandlers.splice(i, 1);
|
|
435
477
|
};
|
|
436
478
|
}
|
|
437
|
-
/**
|
|
479
|
+
/** 销毁实例:解绑消息监听、清空待处理请求、停止握手重试。销毁后实例不可再用 */
|
|
438
480
|
destroy() {
|
|
481
|
+
if (this._destroyed)
|
|
482
|
+
return;
|
|
483
|
+
this._destroyed = true;
|
|
439
484
|
if (this._unlisten) {
|
|
440
485
|
try {
|
|
441
486
|
this._unlisten();
|
|
@@ -448,6 +493,8 @@ export default class LightAppBridge {
|
|
|
448
493
|
clearTimeout(this._handshakeTimer);
|
|
449
494
|
this._handshakeTimer = null;
|
|
450
495
|
}
|
|
496
|
+
// 进行中的握手直接失败(已 resolve 的话 reject 是 no-op)
|
|
497
|
+
this._connectDeferred.reject(new Error('实例已销毁'));
|
|
451
498
|
// 拒绝所有未完成的请求
|
|
452
499
|
this._pending.forEach((p) => {
|
|
453
500
|
clearTimeout(p.timer);
|