@dino-dev/bridge-core-ts 0.0.3 → 0.0.5
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/dist/src/adaptation.d.ts +3 -1
- package/dist/src/adaptation.d.ts.map +1 -1
- package/dist/src/adaptation.js +12 -2
- package/dist/src/adaptation.js.map +1 -1
- package/dist/src/content-protocol.d.ts +43 -0
- package/dist/src/content-protocol.d.ts.map +1 -1
- package/dist/src/content-protocol.js +36 -0
- package/dist/src/content-protocol.js.map +1 -1
- package/dist/src/iframe-host.d.ts +24 -0
- package/dist/src/iframe-host.d.ts.map +1 -0
- package/dist/src/iframe-host.js +138 -0
- package/dist/src/iframe-host.js.map +1 -0
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mock-bridge.d.ts +100 -0
- package/dist/src/mock-bridge.d.ts.map +1 -0
- package/dist/src/mock-bridge.js +247 -0
- package/dist/src/mock-bridge.js.map +1 -0
- package/dist/src/mrp-bridge.d.ts +24 -3
- package/dist/src/mrp-bridge.d.ts.map +1 -1
- package/dist/src/mrp-bridge.js +73 -13
- package/dist/src/mrp-bridge.js.map +1 -1
- package/dist/src/system-module.d.ts +9 -0
- package/dist/src/system-module.d.ts.map +1 -1
- package/dist/src/system-module.js.map +1 -1
- package/package.json +8 -2
- package/src/adaptation.ts +50 -24
- package/src/content-protocol.ts +68 -1
- package/src/iframe-host.ts +169 -0
- package/src/index.ts +37 -22
- package/src/mock-bridge.ts +390 -0
- package/src/mrp-bridge.ts +308 -220
- package/src/system-module.ts +30 -20
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 浏览器 Mock Bridge —— 让 H5 页面脱离 App 容器,在 Chrome 里直接开发调试。
|
|
3
|
+
*
|
|
4
|
+
* 不安装时,浏览器环境下 `whenReady()` 永不 resolve、所有原生调用静默返回 `null`,
|
|
5
|
+
* 页面会停在空状态且不报错。安装后即可拿到可控的假数据与事件。
|
|
6
|
+
*
|
|
7
|
+
* 仅供开发使用,请通过子路径引入,避免被打进生产包:
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* if (import.meta.env.DEV) {
|
|
12
|
+
* const { installMockBridge } = await import('@h5-container/bridge-core-ts/mock');
|
|
13
|
+
* installMockBridge({
|
|
14
|
+
* packageId: 'student_micro_pages',
|
|
15
|
+
* allowedModules: ['user', 'audio', 'navigation'],
|
|
16
|
+
* modules: {
|
|
17
|
+
* user: { getProfile: { userId: '1', nickname: '测试同学' } },
|
|
18
|
+
* audio: { play: async () => ({ ok: true }) },
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import { bridge } from './mrp-bridge';
|
|
25
|
+
// ============================================================
|
|
26
|
+
// 内部状态
|
|
27
|
+
// ============================================================
|
|
28
|
+
const MOCK_FLAG = '__MRP_MOCK_BRIDGE__';
|
|
29
|
+
const DEFAULT_DESIGN_LONG_SIDE = 812;
|
|
30
|
+
const ZERO_SAFE_AREA = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
31
|
+
function buildAdaptation(patch) {
|
|
32
|
+
const screenWidth = patch?.screenWidth ?? window.innerWidth;
|
|
33
|
+
const screenHeight = patch?.screenHeight ?? window.innerHeight;
|
|
34
|
+
const designLongSide = patch?.designLongSide ?? DEFAULT_DESIGN_LONG_SIDE;
|
|
35
|
+
const scale = patch?.scale ?? Math.max(screenWidth, screenHeight) / designLongSide;
|
|
36
|
+
return {
|
|
37
|
+
designLongSide,
|
|
38
|
+
screenWidth,
|
|
39
|
+
screenHeight,
|
|
40
|
+
scale,
|
|
41
|
+
safeArea: patch?.safeArea ?? ZERO_SAFE_AREA,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// ============================================================
|
|
45
|
+
// 安装
|
|
46
|
+
// ============================================================
|
|
47
|
+
/**
|
|
48
|
+
* 安装 Mock Bridge。
|
|
49
|
+
*
|
|
50
|
+
* 已经在真实容器中运行时会直接跳过,因此可以无条件调用。
|
|
51
|
+
*/
|
|
52
|
+
export function installMockBridge(config = {}) {
|
|
53
|
+
const existing = window.__MRP_MOCK__;
|
|
54
|
+
if (existing) {
|
|
55
|
+
console.warn('[Mock Bridge] 已安装,忽略重复调用');
|
|
56
|
+
return existing;
|
|
57
|
+
}
|
|
58
|
+
if (window.__FLUTTER_BRIDGE__) {
|
|
59
|
+
console.info('[Mock Bridge] 检测到真实原生容器,跳过安装');
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const log = config.log ?? true;
|
|
63
|
+
const calls = [];
|
|
64
|
+
let adaptation = buildAdaptation(config.adaptation);
|
|
65
|
+
const previousNativeModules = window.NativeModules;
|
|
66
|
+
const emit = (type, action, payload = {}) => {
|
|
67
|
+
const message = {
|
|
68
|
+
type,
|
|
69
|
+
action,
|
|
70
|
+
payload,
|
|
71
|
+
timestamp: Date.now(),
|
|
72
|
+
};
|
|
73
|
+
if (log) {
|
|
74
|
+
console.log(`[Mock Bridge] → H5 ${type}/${action}`, payload);
|
|
75
|
+
}
|
|
76
|
+
window.dispatchEvent(new CustomEvent('flutterMessage', { detail: message }));
|
|
77
|
+
};
|
|
78
|
+
// ---- system 模块:容器内置,始终可用 ----
|
|
79
|
+
const systemModule = {
|
|
80
|
+
isModuleAllowed: (params) => ({
|
|
81
|
+
allowed: isAllowed(params?.namespace),
|
|
82
|
+
namespace: params?.namespace,
|
|
83
|
+
}),
|
|
84
|
+
getAvailableModules: () => ({
|
|
85
|
+
modules: config.registeredModules ?? config.allowedModules ?? [],
|
|
86
|
+
}),
|
|
87
|
+
getContainerInfo: () => ({
|
|
88
|
+
packageId: config.packageId ?? 'mock_package',
|
|
89
|
+
registeredModules: config.registeredModules ?? config.allowedModules ?? [],
|
|
90
|
+
allowedModules: config.allowedModules ?? null,
|
|
91
|
+
adaptation,
|
|
92
|
+
auth: config.auth,
|
|
93
|
+
debugEnabled: true,
|
|
94
|
+
isMockBridge: true,
|
|
95
|
+
...config.containerInfoExtra,
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
function isAllowed(namespace) {
|
|
99
|
+
if (namespace === 'system')
|
|
100
|
+
return true;
|
|
101
|
+
if (!config.allowedModules)
|
|
102
|
+
return true;
|
|
103
|
+
return config.allowedModules.includes(namespace);
|
|
104
|
+
}
|
|
105
|
+
function resolveImpl(namespace, method) {
|
|
106
|
+
if (namespace === 'system')
|
|
107
|
+
return systemModule[method];
|
|
108
|
+
return config.modules?.[namespace]?.[method];
|
|
109
|
+
}
|
|
110
|
+
// ---- NativeModules 代理 ----
|
|
111
|
+
const moduleProxyCache = new Map();
|
|
112
|
+
function createModuleProxy(namespace) {
|
|
113
|
+
const cached = moduleProxyCache.get(namespace);
|
|
114
|
+
if (cached)
|
|
115
|
+
return cached;
|
|
116
|
+
const proxy = new Proxy({}, {
|
|
117
|
+
// module() 用 `NativeModules[ns][method]` 做存在性判断,必须恒为真
|
|
118
|
+
has: () => true,
|
|
119
|
+
get: (_target, method) => {
|
|
120
|
+
if (typeof method !== 'string')
|
|
121
|
+
return undefined;
|
|
122
|
+
return async (...args) => {
|
|
123
|
+
if (!isAllowed(namespace)) {
|
|
124
|
+
console.error(`[Mock Bridge] 模块 "${namespace}" 不在 allowedModules 中,` +
|
|
125
|
+
`调用 ${namespace}.${method} 被拒绝。` +
|
|
126
|
+
'请检查 package.meta.json 的 allowedModules。');
|
|
127
|
+
return {
|
|
128
|
+
__error__: 'MODULE_ACCESS_DENIED',
|
|
129
|
+
__message__: `Module "${namespace}" not allowed`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const impl = resolveImpl(namespace, method);
|
|
133
|
+
const missing = impl === undefined;
|
|
134
|
+
const result = missing
|
|
135
|
+
? null
|
|
136
|
+
: typeof impl === 'function'
|
|
137
|
+
? await impl(...args)
|
|
138
|
+
: impl;
|
|
139
|
+
calls.push({
|
|
140
|
+
namespace,
|
|
141
|
+
method,
|
|
142
|
+
args,
|
|
143
|
+
result,
|
|
144
|
+
missing,
|
|
145
|
+
timestamp: Date.now(),
|
|
146
|
+
});
|
|
147
|
+
if (missing) {
|
|
148
|
+
console.warn(`[Mock Bridge] 未定义 ${namespace}.${method},返回 null。` +
|
|
149
|
+
`可在 installMockBridge 的 modules.${namespace}.${method} 中补充。`, { args });
|
|
150
|
+
}
|
|
151
|
+
else if (log) {
|
|
152
|
+
console.log(`[Mock Bridge] ${namespace}.${method}`, {
|
|
153
|
+
args,
|
|
154
|
+
result,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
moduleProxyCache.set(namespace, proxy);
|
|
162
|
+
return proxy;
|
|
163
|
+
}
|
|
164
|
+
window.NativeModules = new Proxy({}, {
|
|
165
|
+
has: () => true,
|
|
166
|
+
get: (_target, namespace) => {
|
|
167
|
+
if (typeof namespace !== 'string')
|
|
168
|
+
return undefined;
|
|
169
|
+
return createModuleProxy(namespace);
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// ---- __FLUTTER_BRIDGE__ ----
|
|
173
|
+
window.__FLUTTER_BRIDGE__ = {
|
|
174
|
+
send: async (type, action, payload) => {
|
|
175
|
+
const result = config.onSend?.(type, action, payload) ?? null;
|
|
176
|
+
if (log) {
|
|
177
|
+
console.log(`[Mock Bridge] H5 → ${type}/${action}`, payload);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
},
|
|
181
|
+
onMessage: (jsonString) => {
|
|
182
|
+
try {
|
|
183
|
+
const message = JSON.parse(jsonString);
|
|
184
|
+
emit(message.type, message.action, message.payload);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
console.error('[Mock Bridge] onMessage 解析失败:', e);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
window.__FLUTTER_BRIDGE__[MOCK_FLAG] = true;
|
|
192
|
+
// ---- 窗口尺寸联动 ----
|
|
193
|
+
const handleResize = () => {
|
|
194
|
+
adaptation = buildAdaptation({
|
|
195
|
+
...config.adaptation,
|
|
196
|
+
screenWidth: window.innerWidth,
|
|
197
|
+
screenHeight: window.innerHeight,
|
|
198
|
+
scale: undefined,
|
|
199
|
+
});
|
|
200
|
+
emit('adaptation', 'changed', adaptation);
|
|
201
|
+
};
|
|
202
|
+
const followResize = config.followWindowResize ?? true;
|
|
203
|
+
if (followResize) {
|
|
204
|
+
window.addEventListener('resize', handleResize);
|
|
205
|
+
}
|
|
206
|
+
// ---- 句柄 ----
|
|
207
|
+
const handle = {
|
|
208
|
+
emit,
|
|
209
|
+
setAdaptation(patch) {
|
|
210
|
+
adaptation = buildAdaptation({ ...adaptation, ...patch });
|
|
211
|
+
emit('adaptation', 'changed', adaptation);
|
|
212
|
+
},
|
|
213
|
+
calls,
|
|
214
|
+
printMissing() {
|
|
215
|
+
const missing = calls.filter((c) => c.missing);
|
|
216
|
+
if (missing.length === 0) {
|
|
217
|
+
console.log('[Mock Bridge] 所有原生调用都已命中 mock 定义');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
console.table(missing.map((c) => ({
|
|
221
|
+
调用: `${c.namespace}.${c.method}`,
|
|
222
|
+
参数: JSON.stringify(c.args),
|
|
223
|
+
})));
|
|
224
|
+
},
|
|
225
|
+
uninstall() {
|
|
226
|
+
if (followResize) {
|
|
227
|
+
window.removeEventListener('resize', handleResize);
|
|
228
|
+
}
|
|
229
|
+
delete window.__FLUTTER_BRIDGE__;
|
|
230
|
+
window.NativeModules = previousNativeModules;
|
|
231
|
+
delete window.__MRP_MOCK__;
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
window.__MRP_MOCK__ = handle;
|
|
235
|
+
// 唤醒可能已结束的就绪轮询,让 whenReady() 立即 resolve
|
|
236
|
+
bridge.refreshReady();
|
|
237
|
+
console.info(`[Mock Bridge] 已安装(packageId=${config.packageId ?? 'mock_package'})。` +
|
|
238
|
+
'控制台可用 window.__MRP_MOCK__ 手工触发事件、查看调用记录。');
|
|
239
|
+
return handle;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* 仅在非容器环境安装 mock,在真机/App 中自动跳过。
|
|
243
|
+
*
|
|
244
|
+
* 等价于 `installMockBridge`,语义更明确,适合直接写在入口文件里。
|
|
245
|
+
*/
|
|
246
|
+
export const setupDevBridge = installMockBridge;
|
|
247
|
+
//# sourceMappingURL=mock-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-bridge.js","sourceRoot":"","sources":["../../src/mock-bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/src/mrp-bridge.d.ts
CHANGED
|
@@ -41,6 +41,13 @@ declare global {
|
|
|
41
41
|
NativeModules?: Record<string, Record<string, (...args: unknown[]) => Promise<unknown>>>;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
/** Bridge 就绪状态 */
|
|
45
|
+
export type BridgeReadyState = 'pending' | 'ready' | 'unavailable';
|
|
46
|
+
/** `whenReady()` 选项 */
|
|
47
|
+
export interface WhenReadyOptions {
|
|
48
|
+
/** 超时毫秒数,超时后 Promise 以错误 reject;不传则沿用「永不 reject」的旧行为 */
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
}
|
|
44
51
|
/**
|
|
45
52
|
* Bridge SDK 主类。
|
|
46
53
|
*
|
|
@@ -55,10 +62,25 @@ export declare class MrpBridge {
|
|
|
55
62
|
private _readyPromiseResolve;
|
|
56
63
|
private _readyPromise;
|
|
57
64
|
private _retryCount;
|
|
65
|
+
private _readyState;
|
|
66
|
+
private _readyTimer;
|
|
58
67
|
constructor();
|
|
59
68
|
private _checkReady;
|
|
60
|
-
/**
|
|
61
|
-
|
|
69
|
+
/**
|
|
70
|
+
* 重新触发一次就绪检测。
|
|
71
|
+
*
|
|
72
|
+
* 供 Mock Bridge 在注入后立即生效使用;轮询已结束时也能重新唤醒。
|
|
73
|
+
*/
|
|
74
|
+
refreshReady(): void;
|
|
75
|
+
/** 当前就绪状态:等待中 / 已就绪 / 判定为不在容器环境 */
|
|
76
|
+
get readyState(): BridgeReadyState;
|
|
77
|
+
/**
|
|
78
|
+
* 等待 Bridge 就绪。
|
|
79
|
+
*
|
|
80
|
+
* 默认沿用旧语义:未就绪时 Promise 一直挂起、不会 reject。
|
|
81
|
+
* 传入 `timeoutMs` 可在超时后 reject,便于页面给出明确的错误态。
|
|
82
|
+
*/
|
|
83
|
+
whenReady(options?: WhenReadyOptions): Promise<void>;
|
|
62
84
|
/** 是否在 Flutter WebView 容器中运行 */
|
|
63
85
|
get isInContainer(): boolean;
|
|
64
86
|
/**
|
|
@@ -102,7 +124,6 @@ export declare class MrpBridge {
|
|
|
102
124
|
*/
|
|
103
125
|
module<T extends object = Record<string, (...args: any[]) => Promise<any>>>(namespace: string): T;
|
|
104
126
|
}
|
|
105
|
-
/** Bridge 单例实例 */
|
|
106
127
|
export declare const bridge: MrpBridge;
|
|
107
128
|
export default bridge;
|
|
108
129
|
//# sourceMappingURL=mrp-bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mrp-bridge.d.ts","sourceRoot":"","sources":["../../src/mrp-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"mrp-bridge.d.ts","sourceRoot":"","sources":["../../src/mrp-bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/src/mrp-bridge.js
CHANGED
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* await audio.play({ soundId: 'success', volume: 0.8 });
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
+
import { installIframeHostBridge } from './iframe-host';
|
|
20
|
+
const READY_POLL_INTERVAL_MS = 100;
|
|
21
|
+
const READY_MAX_RETRY = 50;
|
|
22
|
+
// 容器在 onLoadStop(window.onload,需等图片/iframe 等子资源加载完)后才注入
|
|
23
|
+
// __FLUTTER_BRIDGE__,弱网下可能远超 5 秒;已在 WebView 内时不能放弃,否则排队消息全部丢失。
|
|
24
|
+
const READY_SLOW_POLL_INTERVAL_MS = 250;
|
|
19
25
|
// ============================================================
|
|
20
26
|
// MrpBridge
|
|
21
27
|
// ============================================================
|
|
@@ -33,6 +39,8 @@ export class MrpBridge {
|
|
|
33
39
|
this._pendingMessages = [];
|
|
34
40
|
this._readyPromiseResolve = null;
|
|
35
41
|
this._retryCount = 0;
|
|
42
|
+
this._readyState = 'pending';
|
|
43
|
+
this._readyTimer = null;
|
|
36
44
|
this._readyPromise = new Promise((resolve) => {
|
|
37
45
|
this._readyPromiseResolve = resolve;
|
|
38
46
|
});
|
|
@@ -54,29 +62,79 @@ export class MrpBridge {
|
|
|
54
62
|
}
|
|
55
63
|
// ---- 就绪检测 ----
|
|
56
64
|
_checkReady() {
|
|
65
|
+
if (this._readyState === 'ready')
|
|
66
|
+
return;
|
|
57
67
|
if (window.__FLUTTER_BRIDGE__) {
|
|
68
|
+
if (this._readyTimer !== null) {
|
|
69
|
+
clearTimeout(this._readyTimer);
|
|
70
|
+
this._readyTimer = null;
|
|
71
|
+
}
|
|
58
72
|
this._ready = true;
|
|
73
|
+
this._readyState = 'ready';
|
|
59
74
|
this._readyPromiseResolve?.();
|
|
60
75
|
this._pendingMessages.forEach((msg) => this._doSend(msg));
|
|
61
76
|
this._pendingMessages = [];
|
|
77
|
+
return;
|
|
62
78
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
this._retryCount++;
|
|
80
|
+
if (this._retryCount < READY_MAX_RETRY) {
|
|
81
|
+
this._readyTimer = setTimeout(() => this._checkReady(), READY_POLL_INTERVAL_MS);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (window.flutter_inappwebview) {
|
|
85
|
+
this._readyTimer = setTimeout(() => this._checkReady(), READY_SLOW_POLL_INTERVAL_MS);
|
|
86
|
+
return;
|
|
71
87
|
}
|
|
88
|
+
this._readyTimer = null;
|
|
89
|
+
this._readyState = 'unavailable';
|
|
90
|
+
console.error([
|
|
91
|
+
'[MRP Bridge] 等待 %ss 后仍未检测到原生容器(window.__FLUTTER_BRIDGE__)。',
|
|
92
|
+
'· bridge.whenReady() 将永不 resolve,依赖它的页面会一直停在加载态;',
|
|
93
|
+
'· bridge.send() 与原生模块调用都会静默返回 null。',
|
|
94
|
+
'如果当前是在浏览器里开发,请安装 Mock Bridge:',
|
|
95
|
+
" import { installMockBridge } from '@h5-container/bridge-core-ts/mock';",
|
|
96
|
+
].join('\n'), ((READY_MAX_RETRY * READY_POLL_INTERVAL_MS) / 1000).toFixed(1));
|
|
72
97
|
}
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
/**
|
|
99
|
+
* 重新触发一次就绪检测。
|
|
100
|
+
*
|
|
101
|
+
* 供 Mock Bridge 在注入后立即生效使用;轮询已结束时也能重新唤醒。
|
|
102
|
+
*/
|
|
103
|
+
refreshReady() {
|
|
104
|
+
if (this._readyState === 'ready')
|
|
105
|
+
return;
|
|
106
|
+
this._retryCount = 0;
|
|
107
|
+
this._readyState = 'pending';
|
|
108
|
+
this._checkReady();
|
|
109
|
+
}
|
|
110
|
+
/** 当前就绪状态:等待中 / 已就绪 / 判定为不在容器环境 */
|
|
111
|
+
get readyState() {
|
|
112
|
+
return this._readyState;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 等待 Bridge 就绪。
|
|
116
|
+
*
|
|
117
|
+
* 默认沿用旧语义:未就绪时 Promise 一直挂起、不会 reject。
|
|
118
|
+
* 传入 `timeoutMs` 可在超时后 reject,便于页面给出明确的错误态。
|
|
119
|
+
*/
|
|
120
|
+
whenReady(options) {
|
|
121
|
+
const timeoutMs = options?.timeoutMs;
|
|
122
|
+
if (timeoutMs === undefined)
|
|
123
|
+
return this._readyPromise;
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const timer = setTimeout(() => {
|
|
126
|
+
reject(new Error(`[MRP Bridge] 等待原生容器就绪超时(${timeoutMs}ms)。` +
|
|
127
|
+
'当前可能不在容器环境中,浏览器开发请安装 Mock Bridge。'));
|
|
128
|
+
}, timeoutMs);
|
|
129
|
+
void this._readyPromise.then(() => {
|
|
130
|
+
clearTimeout(timer);
|
|
131
|
+
resolve();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
76
134
|
}
|
|
77
135
|
/** 是否在 Flutter WebView 容器中运行 */
|
|
78
136
|
get isInContainer() {
|
|
79
|
-
return !!window.__FLUTTER_BRIDGE__ || !!window.flutter_inappwebview;
|
|
137
|
+
return (!!window.__FLUTTER_BRIDGE__ || !!window.flutter_inappwebview);
|
|
80
138
|
}
|
|
81
139
|
// ---- 消息发送 ----
|
|
82
140
|
/**
|
|
@@ -161,7 +219,8 @@ export class MrpBridge {
|
|
|
161
219
|
// 检查模块访问被拒绝错误
|
|
162
220
|
if (result &&
|
|
163
221
|
typeof result === 'object' &&
|
|
164
|
-
result.__error__ ===
|
|
222
|
+
result.__error__ ===
|
|
223
|
+
'MODULE_ACCESS_DENIED') {
|
|
165
224
|
console.error(`[MRP Bridge] 模块访问被拒绝: ${namespace}.${method}`, result.__message__);
|
|
166
225
|
return null;
|
|
167
226
|
}
|
|
@@ -178,6 +237,7 @@ export class MrpBridge {
|
|
|
178
237
|
// 单例 & 导出
|
|
179
238
|
// ============================================================
|
|
180
239
|
/** Bridge 单例实例 */
|
|
240
|
+
installIframeHostBridge();
|
|
181
241
|
export const bridge = new MrpBridge();
|
|
182
242
|
// 挂载到 window,方便非模块化项目使用
|
|
183
243
|
window.mrpBridge = bridge;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mrp-bridge.js","sourceRoot":"","sources":["../../src/mrp-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"mrp-bridge.js","sourceRoot":"","sources":["../../src/mrp-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,6 +38,15 @@ export interface ArAdaptationInfo {
|
|
|
38
38
|
screenWidth: number;
|
|
39
39
|
screenHeight: number;
|
|
40
40
|
scale: number;
|
|
41
|
+
/** 设备安全区(逻辑像素)。WebView 里 `env(safe-area-inset-*)` 常常拿不到,改由 App 注入。 */
|
|
42
|
+
safeArea?: SafeAreaInsets;
|
|
43
|
+
}
|
|
44
|
+
/** 设备四边的安全区尺寸,单位与 screenWidth/screenHeight 一致。 */
|
|
45
|
+
export interface SafeAreaInsets {
|
|
46
|
+
top: number;
|
|
47
|
+
bottom: number;
|
|
48
|
+
left: number;
|
|
49
|
+
right: number;
|
|
41
50
|
}
|
|
42
51
|
/**
|
|
43
52
|
* 容器内置系统模块接口。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-module.d.ts","sourceRoot":"","sources":["../../src/system-module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,0BAA0B;AAC1B,MAAM,WAAW,mBAAmB;
|
|
1
|
+
{"version":3,"file":"system-module.d.ts","sourceRoot":"","sources":["../../src/system-module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,0BAA0B;AAC1B,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,8BAA8B;AAC9B,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,2BAA2B;AAC3B,MAAM,WAAW,mBAAmB;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,iCAAiC;AACjC,MAAM,WAAW,gBAAgB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAMD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC5B,qBAAqB;IACrB,eAAe,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7E,yBAAyB;IACzB,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACvD,cAAc;IACd,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACjD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-module.js","sourceRoot":"","sources":["../../src/system-module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"system-module.js","sourceRoot":"","sources":["../../src/system-module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA+DtC,+DAA+D;AAC/D,OAAO;AACP,+DAA+D;AAE/D;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe;IAC9B,OAAO,MAAM,CAAC,MAAM,CAAe,QAAQ,CAAC,CAAC;AAC9C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dino-dev/bridge-core-ts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Bridge Core SDK for h5_app_container — H5 ↔ Flutter 通信 + 原生模块类型安全调用(零框架依赖)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"types": "./dist/src/index.d.ts",
|
|
11
11
|
"import": "./dist/src/index.js",
|
|
12
12
|
"default": "./dist/src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./mock": {
|
|
15
|
+
"types": "./dist/src/mock-bridge.d.ts",
|
|
16
|
+
"import": "./dist/src/mock-bridge.js",
|
|
17
|
+
"default": "./dist/src/mock-bridge.js"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
@@ -22,6 +27,7 @@
|
|
|
22
27
|
},
|
|
23
28
|
"scripts": {
|
|
24
29
|
"build": "tsc",
|
|
30
|
+
"test": "node --test test/*.test.mjs",
|
|
25
31
|
"prepublishOnly": "npm run build",
|
|
26
32
|
"release": "npm publish --registry https://registry.npmjs.org",
|
|
27
33
|
"dev": "tsc --watch",
|
|
@@ -42,4 +48,4 @@
|
|
|
42
48
|
"url": "https://github.com/nengli/h5_app_container",
|
|
43
49
|
"directory": "packages/bridge_core_ts"
|
|
44
50
|
}
|
|
45
|
-
}
|
|
51
|
+
}
|
package/src/adaptation.ts
CHANGED
|
@@ -4,54 +4,80 @@
|
|
|
4
4
|
* App 端以 812 作为设计稿最长边基准,将 adaptation 注入 system 模块。
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
getSystemModule,
|
|
9
|
+
type ArAdaptationInfo,
|
|
10
|
+
type SafeAreaInsets,
|
|
11
|
+
} from './system-module';
|
|
8
12
|
import { bridge, type Unsubscribe } from './mrp-bridge';
|
|
9
13
|
|
|
14
|
+
const ZERO_SAFE_AREA: SafeAreaInsets = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
15
|
+
|
|
10
16
|
let currentScale = 1;
|
|
17
|
+
let currentSafeArea: SafeAreaInsets = ZERO_SAFE_AREA;
|
|
11
18
|
let bridgeUnsubscribe: Unsubscribe | null = null;
|
|
12
19
|
const listeners = new Set<ArAdaptationListener>();
|
|
13
20
|
|
|
14
21
|
export type ArAdaptationListener = (adaptation: ArAdaptationInfo) => void;
|
|
15
22
|
|
|
16
|
-
function applyAdaptation(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
function applyAdaptation(
|
|
24
|
+
adaptation: ArAdaptationInfo | null | undefined,
|
|
25
|
+
): ArAdaptationInfo | null {
|
|
26
|
+
if (
|
|
27
|
+
!adaptation ||
|
|
28
|
+
!Number.isFinite(adaptation.scale) ||
|
|
29
|
+
adaptation.scale <= 0
|
|
30
|
+
) {
|
|
31
|
+
currentScale = 1;
|
|
32
|
+
currentSafeArea = ZERO_SAFE_AREA;
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
currentScale = adaptation.scale;
|
|
36
|
+
currentSafeArea = adaptation.safeArea ?? ZERO_SAFE_AREA;
|
|
37
|
+
for (const listener of listeners) {
|
|
38
|
+
listener(adaptation);
|
|
39
|
+
}
|
|
40
|
+
return adaptation;
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
function ensureAdaptationListener(): void {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
if (bridgeUnsubscribe) return;
|
|
45
|
+
bridgeUnsubscribe = bridge.on<ArAdaptationInfo>(
|
|
46
|
+
'adaptation',
|
|
47
|
+
'changed',
|
|
48
|
+
(message) => {
|
|
49
|
+
applyAdaptation(message.payload);
|
|
50
|
+
},
|
|
51
|
+
);
|
|
33
52
|
}
|
|
34
53
|
|
|
35
54
|
/** 从容器读取初始适配信息,并注册横竖屏变化监听。 */
|
|
36
55
|
export async function initArAdaptation(): Promise<ArAdaptationInfo | null> {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
ensureAdaptationListener();
|
|
57
|
+
const info = await getSystemModule().getContainerInfo();
|
|
58
|
+
return applyAdaptation(info?.adaptation);
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
/** 将设计稿尺寸转换为当前 App 屏幕尺寸。 */
|
|
43
62
|
export function ar(value: number): number {
|
|
44
|
-
|
|
63
|
+
return value * currentScale;
|
|
45
64
|
}
|
|
46
65
|
|
|
47
66
|
/** 获取当前适配比例,便于 Canvas 或自定义渲染使用。 */
|
|
48
67
|
export function getArScale(): number {
|
|
49
|
-
|
|
68
|
+
return currentScale;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 获取 App 注入的设备安全区;不在容器内或 App 未注入时返回全 0。 */
|
|
72
|
+
export function getSafeArea(): SafeAreaInsets {
|
|
73
|
+
return currentSafeArea;
|
|
50
74
|
}
|
|
51
75
|
|
|
52
76
|
/** 监听 App 横竖屏或窗口尺寸变化,返回取消监听函数。 */
|
|
53
|
-
export function onArAdaptationChange(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
export function onArAdaptationChange(
|
|
78
|
+
listener: ArAdaptationListener,
|
|
79
|
+
): Unsubscribe {
|
|
80
|
+
ensureAdaptationListener();
|
|
81
|
+
listeners.add(listener);
|
|
82
|
+
return () => listeners.delete(listener);
|
|
57
83
|
}
|