@jhh96/light-app-bridge 1.0.2 → 1.0.4
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 +5 -3
- package/dist/lightAppBridge.d.ts +8 -6
- package/dist/lightAppBridge.js +96 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
| 监听后端 | 优先级 | 适用环境 | 说明 |
|
|
21
21
|
|---------|--------|---------|------|
|
|
22
|
-
| `window.waltz.event.on('native-call-js')` | 高(优先) | 有 waltz 注入的环境 |
|
|
23
|
-
| `window.handleMessageFromNative` | 低(回退) | 无 waltz 的环境 | hook 此全局方法(waltzBridge
|
|
22
|
+
| `window.waltz.event.on('native-call-js')` | 高(优先) | 有 waltz 注入的环境 | 推荐路径,立即可用 |
|
|
23
|
+
| `window.handleMessageFromNative` | 低(回退) | 无 waltz 的环境 | hook 此全局方法(waltzBridge 投递消息的统一入口)。**可能晚于构造注入**,SDK 会轮询等待(上限 10s) |
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
- 两者都始终不可用时,`connect()`/`ready()` reject(构造不抛,因监听后端允许稍后出现)
|
|
26
|
+
- SDK 内部按 waltz → handleMessageFromNative 顺序探测,无需手动指定
|
|
27
|
+
- 握手会等监听就绪后才开始,避免早到的 ack/hello 丢失
|
|
26
28
|
|
|
27
29
|
## 安装(两个项目)
|
|
28
30
|
|
package/dist/lightAppBridge.d.ts
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* 收消息不强依赖 waltz,按以下优先级自动选择监听后端:
|
|
14
14
|
* 1. window.waltz.event.on('native-call-js') —— 有 waltz 的环境(推荐)
|
|
15
|
-
* 2. window.handleMessageFromNative —— 无 waltz
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* 2. window.handleMessageFromNative —— 无 waltz 时由本 SDK 定义此方法
|
|
16
|
+
* (该方法由 waltz.min.js 注册;无 waltz 时为 undefined,renderer 投递消息前
|
|
17
|
+
* 会检查其类型,没人定义则消息被丢弃。故由本 SDK 照 waltz.min.js 方式定义,
|
|
18
|
+
* renderer 收到消息后主动调用它传入消息)
|
|
18
19
|
*
|
|
19
20
|
* 消息信封:
|
|
20
21
|
* { __sdk: 'LightAppBridge', v: 1, id, type, data }
|
|
@@ -68,16 +69,17 @@ export default class LightAppBridge {
|
|
|
68
69
|
private _connectDeferred;
|
|
69
70
|
private _connectPromise;
|
|
70
71
|
private _unlisten;
|
|
72
|
+
private _listenerReady;
|
|
71
73
|
/**
|
|
72
74
|
* @param role 角色,省略时按 window.worklink.plugin 是否存在自动探测
|
|
73
75
|
* @param options 超时配置
|
|
74
|
-
* @throws 依赖未就绪时抛出(window.worklink
|
|
76
|
+
* @throws 依赖未就绪时抛出(window.worklink;监听后端可稍后出现,不算构造失败)
|
|
75
77
|
*/
|
|
76
78
|
constructor(role?: BridgeRole, options?: BridgeOptions);
|
|
77
79
|
/** 校验依赖是否就绪,缺失抛出明确异常 */
|
|
78
80
|
private _checkDeps;
|
|
79
|
-
/** 绑定消息监听:优先 waltz
|
|
80
|
-
private
|
|
81
|
+
/** 绑定消息监听:优先 waltz;无 waltz 时定义/包装 window.handleMessageFromNative */
|
|
82
|
+
private _startListener;
|
|
81
83
|
/** 构造消息信封 */
|
|
82
84
|
private _envelope;
|
|
83
85
|
/** 处理一条归一化后的消息 */
|
package/dist/lightAppBridge.js
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* 收消息不强依赖 waltz,按以下优先级自动选择监听后端:
|
|
14
14
|
* 1. window.waltz.event.on('native-call-js') —— 有 waltz 的环境(推荐)
|
|
15
|
-
* 2. window.handleMessageFromNative —— 无 waltz
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* 2. window.handleMessageFromNative —— 无 waltz 时由本 SDK 定义此方法
|
|
16
|
+
* (该方法由 waltz.min.js 注册;无 waltz 时为 undefined,renderer 投递消息前
|
|
17
|
+
* 会检查其类型,没人定义则消息被丢弃。故由本 SDK 照 waltz.min.js 方式定义,
|
|
18
|
+
* renderer 收到消息后主动调用它传入消息)
|
|
18
19
|
*
|
|
19
20
|
* 消息信封:
|
|
20
21
|
* { __sdk: 'LightAppBridge', v: 1, id, type, data }
|
|
@@ -58,53 +59,63 @@ function hasWaltz() {
|
|
|
58
59
|
return !!(w && w.event && typeof w.event.on === 'function');
|
|
59
60
|
}
|
|
60
61
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
62
|
+
* 解析可用的监听后端并绑定:优先 waltz,回退定义 window.handleMessageFromNative。
|
|
63
|
+
*
|
|
64
|
+
* 说明:handleMessageFromNative 由 waltz.min.js 注册(参考其实现)。
|
|
65
|
+
* 无 waltz 的环境里它是 undefined,且 renderer(waltzBridge preload)投递消息前
|
|
66
|
+
* 会检查 typeof window.handleMessageFromNative === 'function'——
|
|
67
|
+
* 没人定义它消息就会被丢弃。因此无 waltz 时由本 SDK 定义此方法,
|
|
68
|
+
* renderer 收到消息后会主动调用它传入消息。
|
|
63
69
|
*/
|
|
64
|
-
function
|
|
65
|
-
|
|
70
|
+
function bindMessageBackend(cb) {
|
|
71
|
+
const w = window;
|
|
72
|
+
// 1. waltz 路径:有 waltz 的环境(立即可用)
|
|
66
73
|
if (hasWaltz()) {
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
cb(msg);
|
|
72
|
-
};
|
|
73
|
-
window.waltz.event.on('native-call-js', handler);
|
|
74
|
-
return () => {
|
|
75
|
-
var _a;
|
|
76
|
-
const ev = (_a = window.waltz) === null || _a === void 0 ? void 0 : _a.event;
|
|
77
|
-
if (ev && typeof ev.off === 'function')
|
|
78
|
-
ev.off('native-call-js', handler);
|
|
79
|
-
else if (ev && typeof ev.removeListener === 'function')
|
|
80
|
-
ev.removeListener('native-call-js', handler);
|
|
81
|
-
};
|
|
74
|
+
const handler = (raw) => {
|
|
75
|
+
const msg = parseHandleMessageFromNative(raw);
|
|
76
|
+
if (msg)
|
|
77
|
+
cb(msg);
|
|
82
78
|
};
|
|
79
|
+
w.waltz.event.on('native-call-js', handler);
|
|
80
|
+
return Promise.resolve(() => {
|
|
81
|
+
var _a;
|
|
82
|
+
const ev = (_a = w.waltz) === null || _a === void 0 ? void 0 : _a.event;
|
|
83
|
+
if (ev && typeof ev.off === 'function')
|
|
84
|
+
ev.off('native-call-js', handler);
|
|
85
|
+
else if (ev && typeof ev.removeListener === 'function')
|
|
86
|
+
ev.removeListener('native-call-js', handler);
|
|
87
|
+
});
|
|
83
88
|
}
|
|
84
|
-
// 2.
|
|
85
|
-
// waltzBridge
|
|
89
|
+
// 2. 定义 handleMessageFromNative 路径:无 waltz 时。
|
|
90
|
+
// renderer(waltzBridge)投递:handleMessageFromNative(JSON.stringify({responseId, responseData})),
|
|
86
91
|
// 其中 responseData = {code, body:{eventName, params:{message, fromWebContentsId}}, msg}
|
|
87
|
-
if (typeof
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (msg)
|
|
94
|
-
cb(msg);
|
|
95
|
-
// 透传给原 handler(若存在),保持 waltz/业务自身逻辑不被破坏
|
|
96
|
-
if (typeof prev === 'function')
|
|
97
|
-
return prev.apply(this, arguments);
|
|
98
|
-
};
|
|
99
|
-
w.handleMessageFromNative = wrapped;
|
|
100
|
-
return () => {
|
|
101
|
-
// 还原:仅当仍为自身 wrapped 时才还原,避免覆盖后续可能的重新赋值
|
|
102
|
-
if (w.handleMessageFromNative === wrapped)
|
|
103
|
-
w.handleMessageFromNative = prev;
|
|
104
|
-
};
|
|
92
|
+
if (typeof w.handleMessageFromNative !== 'function') {
|
|
93
|
+
// 尚未定义(无 waltz 的正常情况):由本 SDK 定义,renderer 主动调它传消息
|
|
94
|
+
const handler = function (raw) {
|
|
95
|
+
const msg = parseHandleMessageFromNative(raw);
|
|
96
|
+
if (msg)
|
|
97
|
+
cb(msg);
|
|
105
98
|
};
|
|
99
|
+
w.handleMessageFromNative = handler;
|
|
100
|
+
return Promise.resolve(() => {
|
|
101
|
+
// 清理:仅当仍为自身 handler 时才删除,避免误删后续重新赋值
|
|
102
|
+
if (w.handleMessageFromNative === handler)
|
|
103
|
+
delete w.handleMessageFromNative;
|
|
104
|
+
});
|
|
106
105
|
}
|
|
107
|
-
|
|
106
|
+
// 已存在(如 waltz 晚于本 SDK 加载、或其它实例已定义):包装透传,不破坏原逻辑
|
|
107
|
+
const prev = w.handleMessageFromNative;
|
|
108
|
+
const wrapped = function (raw) {
|
|
109
|
+
const msg = parseHandleMessageFromNative(raw);
|
|
110
|
+
if (msg)
|
|
111
|
+
cb(msg);
|
|
112
|
+
return prev.apply(this, arguments);
|
|
113
|
+
};
|
|
114
|
+
w.handleMessageFromNative = wrapped;
|
|
115
|
+
return Promise.resolve(() => {
|
|
116
|
+
if (w.handleMessageFromNative === wrapped)
|
|
117
|
+
w.handleMessageFromNative = prev;
|
|
118
|
+
});
|
|
108
119
|
}
|
|
109
120
|
/**
|
|
110
121
|
* 解析 handleMessageFromNative / waltz native-call-js 的统一数据格式。
|
|
@@ -137,7 +148,7 @@ export default class LightAppBridge {
|
|
|
137
148
|
/**
|
|
138
149
|
* @param role 角色,省略时按 window.worklink.plugin 是否存在自动探测
|
|
139
150
|
* @param options 超时配置
|
|
140
|
-
* @throws 依赖未就绪时抛出(window.worklink
|
|
151
|
+
* @throws 依赖未就绪时抛出(window.worklink;监听后端可稍后出现,不算构造失败)
|
|
141
152
|
*/
|
|
142
153
|
constructor(role, options = {}) {
|
|
143
154
|
this._pending = new Map();
|
|
@@ -151,6 +162,7 @@ export default class LightAppBridge {
|
|
|
151
162
|
this._handshakeTimer = null;
|
|
152
163
|
this._started = false;
|
|
153
164
|
this._unlisten = null;
|
|
165
|
+
this._listenerReady = null;
|
|
154
166
|
let r = role === 'plugin' || role === 'lightapp' ? role : 'lightapp';
|
|
155
167
|
if (role !== 'plugin' && role !== 'lightapp') {
|
|
156
168
|
const wl = window.worklink;
|
|
@@ -166,8 +178,8 @@ export default class LightAppBridge {
|
|
|
166
178
|
return peerId;
|
|
167
179
|
});
|
|
168
180
|
this._checkDeps(); // 依赖校验,缺失直接抛异常
|
|
169
|
-
this.
|
|
170
|
-
this.connect(); //
|
|
181
|
+
this._startListener(); // 绑定消息监听(waltz 或定义 handleMessageFromNative)
|
|
182
|
+
this.connect(); // 构造即自动发起握手(内部会等监听就绪)
|
|
171
183
|
}
|
|
172
184
|
/** 校验依赖是否就绪,缺失抛出明确异常 */
|
|
173
185
|
_checkDeps() {
|
|
@@ -178,17 +190,23 @@ export default class LightAppBridge {
|
|
|
178
190
|
if (this.role === 'plugin' && typeof (w.worklink.plugin && w.worklink.plugin.getContentContext) !== 'function') {
|
|
179
191
|
throw new Error('LightAppBridge(plugin) 依赖 window.worklink.plugin.getContentContext,当前环境不可用');
|
|
180
192
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
193
|
+
// 监听后端不强校验:有 waltz 走 waltz;无 waltz 由 _startListener 定义
|
|
194
|
+
// window.handleMessageFromNative(renderer 会主动调用它传入消息)。
|
|
184
195
|
}
|
|
185
|
-
/** 绑定消息监听:优先 waltz
|
|
186
|
-
|
|
196
|
+
/** 绑定消息监听:优先 waltz;无 waltz 时定义/包装 window.handleMessageFromNative */
|
|
197
|
+
_startListener() {
|
|
187
198
|
if (this._started)
|
|
188
199
|
return;
|
|
189
200
|
this._started = true;
|
|
190
|
-
|
|
191
|
-
|
|
201
|
+
this._listenerReady = bindMessageBackend((msg) => this._onMessage(msg))
|
|
202
|
+
.then((unlisten) => {
|
|
203
|
+
this._unlisten = unlisten;
|
|
204
|
+
})
|
|
205
|
+
.catch((e) => {
|
|
206
|
+
// 理论上不会发生(无 waltz 时必走定义路径),保险起见让连接失败并给出原因
|
|
207
|
+
this._connectDeferred.reject(new Error('LightAppBridge 监听后端绑定失败 (' +
|
|
208
|
+
(e && e.message ? e.message : String(e)) + ')'));
|
|
209
|
+
});
|
|
192
210
|
}
|
|
193
211
|
/** 构造消息信封 */
|
|
194
212
|
_envelope(type, data, id = genId()) {
|
|
@@ -225,9 +243,12 @@ export default class LightAppBridge {
|
|
|
225
243
|
* @returns 对端 webContentsId
|
|
226
244
|
*/
|
|
227
245
|
connect() {
|
|
246
|
+
var _a;
|
|
228
247
|
if (this._connectStarted)
|
|
229
248
|
return this._connectPromise;
|
|
230
249
|
this._connectStarted = true;
|
|
250
|
+
// 等监听后端绑定完成后再握手,避免对端的 ack/hello 在监听绑定前到达而丢失
|
|
251
|
+
const listenerReady = (_a = this._listenerReady) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
231
252
|
// 握手超时保护
|
|
232
253
|
this._handshakeTimer = setTimeout(() => {
|
|
233
254
|
if (!this._connected) {
|
|
@@ -235,24 +256,28 @@ export default class LightAppBridge {
|
|
|
235
256
|
this._clearHelloTimer();
|
|
236
257
|
}
|
|
237
258
|
}, this.handshakeTimeout);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
listenerReady
|
|
260
|
+
.then(() => {
|
|
261
|
+
if (this._connected)
|
|
262
|
+
return;
|
|
263
|
+
if (this.role === 'plugin') {
|
|
264
|
+
// 插件:解析目标后发 hello,并重试直到收到 ack
|
|
265
|
+
return window.worklink.plugin.getContentContext()
|
|
266
|
+
.then((ctx) => {
|
|
267
|
+
if (!ctx || ctx.webContentsId == null) {
|
|
268
|
+
throw new Error('getContentContext 未返回 webContentsId');
|
|
269
|
+
}
|
|
270
|
+
this._target = ctx.webContentsId;
|
|
271
|
+
this._sendHello();
|
|
272
|
+
this._helloTimer = setInterval(() => {
|
|
273
|
+
if (!this._connected)
|
|
274
|
+
this._sendHello();
|
|
275
|
+
}, HELLO_RETRY_INTERVAL);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// lightapp 被动等待 hello(listener 已绑定),收到后在 _onHello 中回 ack 并 resolve
|
|
279
|
+
})
|
|
280
|
+
.catch((e) => this._connectDeferred.reject(e));
|
|
256
281
|
return this._connectPromise;
|
|
257
282
|
}
|
|
258
283
|
/** 发送 hello(携带自身 webContentsId) */
|