@beppla/tapas-ui 1.2.9 → 1.2.10
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/commonjs/WebViewBridge/README.md +536 -0
- package/commonjs/WebViewBridge/WebViewBridge.js +741 -0
- package/commonjs/WebViewBridge/WebViewBridge.js.map +1 -0
- package/commonjs/WebViewBridge/index.js +32 -0
- package/commonjs/WebViewBridge/index.js.map +1 -0
- package/commonjs/WebViewBridge/useWebViewBridge.js +89 -0
- package/commonjs/WebViewBridge/useWebViewBridge.js.map +1 -0
- package/commonjs/index.js +31 -0
- package/commonjs/index.js.map +1 -1
- package/module/WebViewBridge/README.md +536 -0
- package/module/WebViewBridge/WebViewBridge.js +733 -0
- package/module/WebViewBridge/WebViewBridge.js.map +1 -0
- package/module/WebViewBridge/index.js +5 -0
- package/module/WebViewBridge/index.js.map +1 -0
- package/module/WebViewBridge/useWebViewBridge.js +83 -0
- package/module/WebViewBridge/useWebViewBridge.js.map +1 -0
- package/module/index.js +2 -0
- package/module/index.js.map +1 -1
- package/package.json +1 -1
- package/typescript/WebViewBridge/WebViewBridge.d.ts +132 -0
- package/typescript/WebViewBridge/WebViewBridge.d.ts.map +1 -0
- package/typescript/WebViewBridge/index.d.ts +3 -0
- package/typescript/WebViewBridge/index.d.ts.map +1 -0
- package/typescript/WebViewBridge/useWebViewBridge.d.ts +55 -0
- package/typescript/WebViewBridge/useWebViewBridge.d.ts.map +1 -0
- package/typescript/index.d.ts +2 -0
- package/typescript/index.d.ts.map +1 -1
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# WebViewBridge 组件
|
|
2
|
+
|
|
3
|
+
WebView/iframe 通信桥接组件,用于 RN Web 模块与 tapas-sys 底座之间的通信。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ **自动环境检测**:自动判断运行在 Android/iOS WebView 或 Web iframe 环境
|
|
8
|
+
- ✅ **统一消息格式**:自动适配不同环境的消息格式差异
|
|
9
|
+
- ✅ **消息监听**:支持全局和类型特定的消息监听
|
|
10
|
+
- ✅ **自动初始化**:组件挂载后,在 window.onload 完成时自动发送初始化消息给 tapas-sys(默认行为)
|
|
11
|
+
- ✅ **类型安全**:完整的 TypeScript 类型定义
|
|
12
|
+
- ✅ **易于使用**:提供 Hook 简化使用
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
yarn add @beppla/tapas-ui
|
|
18
|
+
# 或
|
|
19
|
+
npm install @beppla/tapas-ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 基础用法
|
|
23
|
+
|
|
24
|
+
### 方式一:使用组件
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import React from 'react';
|
|
28
|
+
import { WebViewBridge, WebViewMessage, WebViewBridgeRef } from '@beppla/tapas-ui';
|
|
29
|
+
|
|
30
|
+
function MyComponent() {
|
|
31
|
+
const bridgeRef = React.useRef<WebViewBridgeRef>(null);
|
|
32
|
+
|
|
33
|
+
const handleMessage = (message: WebViewMessage) => {
|
|
34
|
+
console.log('收到消息:', message);
|
|
35
|
+
console.log('消息来源:', message.from); // 来自 tapas-sys 的消息
|
|
36
|
+
|
|
37
|
+
if (message.type === 'userInfo') {
|
|
38
|
+
console.log('用户信息:', message.payload);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const sendDataToTapasSys = () => {
|
|
43
|
+
// 向 tapas-sys 发送消息(自动包含 from 字段并 base64 加密)
|
|
44
|
+
if (bridgeRef.current) {
|
|
45
|
+
bridgeRef.current.sendMessage('requestData', {
|
|
46
|
+
moduleId: 'myModule',
|
|
47
|
+
action: 'getUserInfo'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<WebViewBridge
|
|
55
|
+
ref={bridgeRef}
|
|
56
|
+
from="MyRNWebModule" // 必需:标识消息来源
|
|
57
|
+
onMessage={handleMessage}
|
|
58
|
+
initPayload={{ moduleName: 'MyModule', version: '1.0.0' }}
|
|
59
|
+
autoInit={true}
|
|
60
|
+
enableBase64={true} // 默认启用 base64 加密
|
|
61
|
+
/>
|
|
62
|
+
<button onClick={sendDataToTapasSys}>发送消息到 tapas-sys</button>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 方式二:使用 Hook(推荐)
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import React from 'react';
|
|
72
|
+
import { useWebViewBridge } from '@beppla/tapas-ui';
|
|
73
|
+
|
|
74
|
+
function MyComponent() {
|
|
75
|
+
const { bridgeRef, sendMessage, handleMessage } = useWebViewBridge({
|
|
76
|
+
onMessage: (message) => {
|
|
77
|
+
console.log('收到消息:', message);
|
|
78
|
+
console.log('消息来源:', message.from);
|
|
79
|
+
},
|
|
80
|
+
messageHandlers: {
|
|
81
|
+
'userInfo': (message) => {
|
|
82
|
+
console.log('用户信息:', message.payload);
|
|
83
|
+
},
|
|
84
|
+
'config': (message) => {
|
|
85
|
+
console.log('配置信息:', message.payload);
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const handleButtonClick = () => {
|
|
91
|
+
// 发送的消息会自动包含 from 字段并 base64 加密
|
|
92
|
+
sendMessage('requestData', { id: 123 });
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<>
|
|
97
|
+
<WebViewBridge
|
|
98
|
+
ref={bridgeRef}
|
|
99
|
+
from="MyRNWebModule" // 必需:标识消息来源
|
|
100
|
+
onMessage={handleMessage}
|
|
101
|
+
initPayload={{ moduleName: 'MyModule' }}
|
|
102
|
+
enableBase64={true} // 默认启用 base64 加密
|
|
103
|
+
/>
|
|
104
|
+
<button onClick={handleButtonClick}>请求数据</button>
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## API 参考
|
|
111
|
+
|
|
112
|
+
### WebViewBridge Props
|
|
113
|
+
|
|
114
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
115
|
+
|------|------|--------|------|
|
|
116
|
+
| `from` | `string` | - | **消息来源标识**(**必需**),用于标识 RN Web 模块,会作为消息的 from 字段发送给 tapas-sys |
|
|
117
|
+
| `onMessage` | `(message: WebViewMessage) => void` | - | 消息监听回调 |
|
|
118
|
+
| `onError` | `(error: Error, context?: { type: 'send' \| 'receive' \| 'parse' \| 'origin' }) => void` | - | **错误回调**,当发送/接收/解析消息或 origin 验证失败时触发 |
|
|
119
|
+
| `initPayload` | `any` | - | 初始化消息的 payload |
|
|
120
|
+
| `autoInit` | `boolean` | `true` | **是否自动发送初始化消息**(默认 true)。组件会在 window.onload 完成后自动发送初始化消息给 tapas-sys |
|
|
121
|
+
| `initMessageType` | `string` | `'init'` | 初始化消息类型(默认 'init') |
|
|
122
|
+
| `enableBase64` | `boolean` | `true` | **是否启用 base64 加密**(默认 true,符合 tapas-sys 解析格式) |
|
|
123
|
+
| `showPlaceholder` | `boolean` | `true` | 是否显示占位 DOM |
|
|
124
|
+
| `style` | `StyleProp<ViewStyle>` | - | 自定义样式 |
|
|
125
|
+
| `testID` | `string` | - | 测试 ID |
|
|
126
|
+
| `allowedOrigins` | `string[]` | - | **安全性:允许的消息来源(origin)白名单**。在 iframe 环境中,只有来自这些 origin 的消息才会被处理。支持通配符(如 `'https://*.example.com'`) |
|
|
127
|
+
| `strictOriginCheck` | `boolean` | `false` | **安全性:是否严格验证 origin**。`true`: 如果消息来源不在白名单中,直接拒绝;`false`: 仅警告,但仍处理消息(开发环境) |
|
|
128
|
+
| `allowedFrom` | `string[]` | - | **安全性:只接收来自特定 from 的消息**。如果设置,只有 from 字段匹配的消息才会被处理 |
|
|
129
|
+
| `messageFilter` | `(message: WebViewMessage) => boolean` | - | **消息过滤器函数**。返回 `true` 表示处理该消息,`false` 表示忽略 |
|
|
130
|
+
| `debug` | `boolean` | `false` | **调试模式**。启用后会输出详细的日志信息 |
|
|
131
|
+
| `logLevel` | `'none' \| 'error' \| 'warn' \| 'info' \| 'debug'` | `'warn'` | **日志级别**。控制输出的日志详细程度 |
|
|
132
|
+
|
|
133
|
+
### WebViewBridgeRef 方法
|
|
134
|
+
|
|
135
|
+
| 方法 | 说明 |
|
|
136
|
+
|------|------|
|
|
137
|
+
| `sendMessage(type: string, payload?: any): boolean` | **发送消息到 tapas-sys 底座**(支持 WebView 和 iframe 两种环境)。返回 `true` 表示发送成功,`false` 表示失败 |
|
|
138
|
+
| `getEnvironment(): 'webview' \| 'iframe' \| 'unknown'` | 获取当前运行环境 |
|
|
139
|
+
| `cleanup(): void` | **清理所有监听器和资源**。组件卸载时会自动调用,也可手动调用 |
|
|
140
|
+
|
|
141
|
+
### 发送消息到 tapas-sys
|
|
142
|
+
|
|
143
|
+
组件提供了完整的消息发送功能,**RN Web 模块可以通过以下方式向 tapas-sys 发送消息**:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// 方式一:通过 ref
|
|
147
|
+
const bridgeRef = useRef<WebViewBridgeRef>(null);
|
|
148
|
+
|
|
149
|
+
bridgeRef.current?.sendMessage('requestData', { id: 123 });
|
|
150
|
+
|
|
151
|
+
// 方式二:通过 Hook
|
|
152
|
+
const { sendMessage } = useWebViewBridge();
|
|
153
|
+
|
|
154
|
+
sendMessage('requestData', { id: 123 });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**发送机制**:
|
|
158
|
+
- **Android/iOS WebView**:使用 `window.ReactNativeWebView.postMessage()`
|
|
159
|
+
- **Web iframe**:使用 `window.parent.postMessage()`
|
|
160
|
+
- **自动降级**:如果主要方式失败,会自动尝试其他方式
|
|
161
|
+
|
|
162
|
+
### WebViewMessage 类型
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
interface WebViewMessage {
|
|
166
|
+
type: string; // 消息类型
|
|
167
|
+
payload?: any; // 消息数据
|
|
168
|
+
timestamp?: number; // 时间戳
|
|
169
|
+
id?: string; // 消息 ID
|
|
170
|
+
from?: string; // 消息来源标识(RN Web 模块标识)
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 原生 WebView 集成
|
|
175
|
+
|
|
176
|
+
### React Native WebView
|
|
177
|
+
|
|
178
|
+
如果使用 `react-native-webview`,需要配置如下:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { WebView } from 'react-native-webview';
|
|
182
|
+
import { WebViewBridge, handleNativeWebViewMessage } from '@beppla/tapas-ui';
|
|
183
|
+
|
|
184
|
+
function App() {
|
|
185
|
+
const handleWebViewMessage = (event: any) => {
|
|
186
|
+
handleNativeWebViewMessage(event, (message) => {
|
|
187
|
+
console.log('收到消息:', message);
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<WebView
|
|
193
|
+
source={{ uri: 'https://your-app.com' }}
|
|
194
|
+
onMessage={handleWebViewMessage}
|
|
195
|
+
injectedJavaScript={createWebViewInjectedScript()}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Expo WebView
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { WebView } from 'react-native-webview';
|
|
205
|
+
import { WebViewBridge, createWebViewInjectedScript } from '@beppla/tapas-ui';
|
|
206
|
+
|
|
207
|
+
function App() {
|
|
208
|
+
return (
|
|
209
|
+
<WebView
|
|
210
|
+
source={{ uri: 'https://your-app.com' }}
|
|
211
|
+
injectedJavaScript={createWebViewInjectedScript()}
|
|
212
|
+
/>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 消息格式
|
|
218
|
+
|
|
219
|
+
### 发送消息
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// 使用 from 字段标识消息来源
|
|
223
|
+
<WebViewBridge
|
|
224
|
+
from="MyRNWebModule"
|
|
225
|
+
enableBase64={true}
|
|
226
|
+
/>
|
|
227
|
+
|
|
228
|
+
// 发送消息
|
|
229
|
+
sendMessage('requestData', { id: 123 });
|
|
230
|
+
|
|
231
|
+
// 实际构建的消息对象:
|
|
232
|
+
{
|
|
233
|
+
type: 'requestData',
|
|
234
|
+
payload: { id: 123 },
|
|
235
|
+
timestamp: 1234567890,
|
|
236
|
+
id: 'msg_1234567890_1',
|
|
237
|
+
from: 'MyRNWebModule' // 自动添加
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 发送流程:
|
|
241
|
+
// 1. JSON.stringify(message) → JSON 字符串
|
|
242
|
+
// 2. Base64 编码 → base64 字符串
|
|
243
|
+
// 3. 通过 postMessage 发送给 tapas-sys
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Base64 加密
|
|
247
|
+
|
|
248
|
+
组件默认启用 base64 加密,符合 tapas-sys 的解析格式:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
// 启用 base64(默认)
|
|
252
|
+
<WebViewBridge from="MyModule" enableBase64={true} />
|
|
253
|
+
|
|
254
|
+
// 禁用 base64(仅用于调试)
|
|
255
|
+
<WebViewBridge from="MyModule" enableBase64={false} />
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**消息加密流程**:
|
|
259
|
+
1. 构建消息对象(包含 `from` 字段)
|
|
260
|
+
2. `JSON.stringify()` 转为 JSON 字符串
|
|
261
|
+
3. Base64 编码
|
|
262
|
+
4. 通过 `postMessage` 发送
|
|
263
|
+
|
|
264
|
+
**消息解密流程**(接收时):
|
|
265
|
+
1. 接收 base64 字符串
|
|
266
|
+
2. Base64 解码
|
|
267
|
+
3. `JSON.parse()` 解析
|
|
268
|
+
4. 触发 `onMessage` 回调
|
|
269
|
+
|
|
270
|
+
### 接收消息
|
|
271
|
+
|
|
272
|
+
组件会自动处理不同环境的消息格式差异,并自动进行 base64 解码:
|
|
273
|
+
|
|
274
|
+
- **WebView 环境**:从 `event.nativeEvent.data` 或 `event.data` 解析(自动 base64 解码)
|
|
275
|
+
- **iframe 环境**:从 `event.data` 解析(自动 base64 解码)
|
|
276
|
+
|
|
277
|
+
**注意**:如果消息不是 base64 编码的,组件会自动降级为直接 JSON 解析
|
|
278
|
+
|
|
279
|
+
### 自动初始化消息
|
|
280
|
+
|
|
281
|
+
**组件会在 window.onload 完成后自动发送初始化消息给 tapas-sys**,这是组件的默认行为,无需手动调用:
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
<WebViewBridge
|
|
285
|
+
from="MyRNWebModule" // 必需:标识消息来源
|
|
286
|
+
autoInit={true} // 默认 true,在 window.onload 完成后自动发送
|
|
287
|
+
initMessageType="init" // 默认 'init'
|
|
288
|
+
initPayload={{ moduleName: 'MyModule', version: '1.0.0' }}
|
|
289
|
+
enableBase64={true} // 默认 true,消息会进行 base64 编码
|
|
290
|
+
/>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**初始化流程**:
|
|
294
|
+
1. 组件挂载后,检测 `document.readyState`
|
|
295
|
+
2. 如果文档已加载完成(`complete` 或 `interactive`),立即发送初始化消息
|
|
296
|
+
3. 如果文档还在加载,等待 `window.onload` 事件
|
|
297
|
+
4. 发送的消息格式:`{ type: 'init', payload: {...}, from: 'MyRNWebModule', ... }`
|
|
298
|
+
5. 消息会自动进行 base64 编码后发送给 tapas-sys
|
|
299
|
+
|
|
300
|
+
**重要说明**:
|
|
301
|
+
- `from` 字段是**必需的**,用于标识 RN Web 模块,tapas-sys 需要此字段来识别消息来源
|
|
302
|
+
- 初始化消息会在 RN web 项目完全加载后(window.onload)自动发送,确保所有资源都已就绪
|
|
303
|
+
- 如果不需要自动初始化,可以设置 `autoInit={false}`,然后手动调用 `sendMessage('init', {...})`
|
|
304
|
+
|
|
305
|
+
## 运行环境检测
|
|
306
|
+
|
|
307
|
+
组件会自动检测运行环境:
|
|
308
|
+
|
|
309
|
+
- **Android/iOS**:检测为 `'webview'`
|
|
310
|
+
- **Web(iframe)**:检测为 `'iframe'`
|
|
311
|
+
- **未知环境**:检测为 `'unknown'`
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
const { getEnvironment } = useWebViewBridge();
|
|
315
|
+
|
|
316
|
+
const env = getEnvironment();
|
|
317
|
+
console.log('当前环境:', env); // 'webview' | 'iframe' | 'unknown'
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 最佳实践
|
|
321
|
+
|
|
322
|
+
### 1. 使用 Hook 简化代码
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
const { bridgeRef, sendMessage, handleMessage } = useWebViewBridge({
|
|
326
|
+
messageHandlers: {
|
|
327
|
+
'userInfo': handleUserInfo,
|
|
328
|
+
'config': handleConfig,
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 2. 注册特定类型的处理器
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
const { registerHandler } = useWebViewBridge();
|
|
337
|
+
|
|
338
|
+
useEffect(() => {
|
|
339
|
+
const unregister = registerHandler('customType', (message) => {
|
|
340
|
+
// 处理特定类型的消息
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
return unregister; // 清理
|
|
344
|
+
}, []);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 3. 错误处理
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
const handleMessage = (message: WebViewMessage) => {
|
|
351
|
+
try {
|
|
352
|
+
// 处理消息
|
|
353
|
+
} catch (error) {
|
|
354
|
+
console.error('消息处理错误:', error);
|
|
355
|
+
sendMessage('error', { error: error.message });
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 4. 消息确认机制
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
const sendMessageWithAck = async (type: string, payload: any) => {
|
|
364
|
+
const messageId = `msg_${Date.now()}`;
|
|
365
|
+
|
|
366
|
+
return new Promise((resolve, reject) => {
|
|
367
|
+
const timeout = setTimeout(() => {
|
|
368
|
+
reject(new Error('消息超时'));
|
|
369
|
+
}, 5000);
|
|
370
|
+
|
|
371
|
+
const handler = (message: WebViewMessage) => {
|
|
372
|
+
if (message.id === messageId) {
|
|
373
|
+
clearTimeout(timeout);
|
|
374
|
+
resolve(message);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
registerHandler('ack', handler);
|
|
379
|
+
sendMessage(type, { ...payload, messageId });
|
|
380
|
+
});
|
|
381
|
+
};
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## 安全性配置
|
|
385
|
+
|
|
386
|
+
### Origin 验证
|
|
387
|
+
|
|
388
|
+
在生产环境中,强烈建议配置 `allowedOrigins` 和 `strictOriginCheck` 来确保消息来源可信:
|
|
389
|
+
|
|
390
|
+
```tsx
|
|
391
|
+
<WebViewBridge
|
|
392
|
+
from="MyRNWebModule"
|
|
393
|
+
allowedOrigins={[
|
|
394
|
+
'https://tapas-sys.example.com',
|
|
395
|
+
'https://*.example.com', // 支持通配符
|
|
396
|
+
]}
|
|
397
|
+
strictOriginCheck={true} // 生产环境建议设为 true
|
|
398
|
+
onError={(error, context) => {
|
|
399
|
+
if (context?.type === 'origin') {
|
|
400
|
+
console.error('消息来源验证失败:', error);
|
|
401
|
+
// 可以上报安全事件
|
|
402
|
+
}
|
|
403
|
+
}}
|
|
404
|
+
/>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 消息来源过滤
|
|
408
|
+
|
|
409
|
+
可以限制只接收来自特定 `from` 的消息:
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
<WebViewBridge
|
|
413
|
+
from="MyRNWebModule"
|
|
414
|
+
allowedFrom={['tapas-sys', 'other-module']} // 只接收来自这些模块的消息
|
|
415
|
+
onMessage={handleMessage}
|
|
416
|
+
/>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### 消息过滤器
|
|
420
|
+
|
|
421
|
+
使用自定义过滤器函数来过滤消息:
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
<WebViewBridge
|
|
425
|
+
from="MyRNWebModule"
|
|
426
|
+
messageFilter={(message) => {
|
|
427
|
+
// 只处理特定类型的消息
|
|
428
|
+
return message.type === 'userInfo' || message.type === 'config';
|
|
429
|
+
}}
|
|
430
|
+
onMessage={handleMessage}
|
|
431
|
+
/>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## 调试和日志
|
|
435
|
+
|
|
436
|
+
### 调试模式
|
|
437
|
+
|
|
438
|
+
启用调试模式可以查看详细的日志信息:
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
<WebViewBridge
|
|
442
|
+
from="MyRNWebModule"
|
|
443
|
+
debug={true} // 启用调试模式
|
|
444
|
+
logLevel="debug" // 输出所有日志
|
|
445
|
+
onMessage={handleMessage}
|
|
446
|
+
/>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### 日志级别
|
|
450
|
+
|
|
451
|
+
- `'none'`: 不输出任何日志
|
|
452
|
+
- `'error'`: 仅输出错误
|
|
453
|
+
- `'warn'`: 输出警告和错误(默认)
|
|
454
|
+
- `'info'`: 输出信息、警告和错误
|
|
455
|
+
- `'debug'`: 输出所有日志(包括调试信息)
|
|
456
|
+
|
|
457
|
+
## 错误处理
|
|
458
|
+
|
|
459
|
+
### 错误回调
|
|
460
|
+
|
|
461
|
+
使用 `onError` 回调来处理各种错误:
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
<WebViewBridge
|
|
465
|
+
from="MyRNWebModule"
|
|
466
|
+
onError={(error, context) => {
|
|
467
|
+
switch (context?.type) {
|
|
468
|
+
case 'send':
|
|
469
|
+
console.error('发送消息失败:', error);
|
|
470
|
+
// 可以重试或上报
|
|
471
|
+
break;
|
|
472
|
+
case 'receive':
|
|
473
|
+
console.error('接收消息失败:', error);
|
|
474
|
+
break;
|
|
475
|
+
case 'parse':
|
|
476
|
+
console.error('解析消息失败:', error);
|
|
477
|
+
break;
|
|
478
|
+
case 'origin':
|
|
479
|
+
console.error('Origin 验证失败:', error);
|
|
480
|
+
// 安全事件,应该上报
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
}}
|
|
484
|
+
/>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### 发送状态检查
|
|
488
|
+
|
|
489
|
+
`sendMessage` 现在返回布尔值,表示是否发送成功:
|
|
490
|
+
|
|
491
|
+
```tsx
|
|
492
|
+
const bridgeRef = useRef<WebViewBridgeRef>(null);
|
|
493
|
+
|
|
494
|
+
const handleSend = () => {
|
|
495
|
+
if (bridgeRef.current) {
|
|
496
|
+
const success = bridgeRef.current.sendMessage('requestData', { id: 123 });
|
|
497
|
+
if (!success) {
|
|
498
|
+
console.error('消息发送失败');
|
|
499
|
+
// 可以重试
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
## 注意事项
|
|
506
|
+
|
|
507
|
+
1. **安全性**:在生产环境中,**必须**配置 `allowedOrigins` 和 `strictOriginCheck={true}` 确保消息来源可信
|
|
508
|
+
2. **性能**:避免在消息处理器中执行耗时操作
|
|
509
|
+
3. **内存泄漏**:记得清理注册的处理器,组件卸载时会自动清理
|
|
510
|
+
4. **兼容性**:确保父窗口/WebView 支持 postMessage API
|
|
511
|
+
5. **调试**:开发环境可以使用 `debug={true}` 和 `logLevel="debug"` 来查看详细日志,生产环境建议使用 `logLevel="error"` 或 `"warn"`
|
|
512
|
+
|
|
513
|
+
## 故障排查
|
|
514
|
+
|
|
515
|
+
### 消息无法发送
|
|
516
|
+
|
|
517
|
+
1. 检查运行环境是否正确检测
|
|
518
|
+
2. 确认父窗口/WebView 存在
|
|
519
|
+
3. 检查控制台是否有错误信息
|
|
520
|
+
|
|
521
|
+
### 消息无法接收
|
|
522
|
+
|
|
523
|
+
1. 确认已正确配置 `onMessage` 回调
|
|
524
|
+
2. 检查消息格式是否正确
|
|
525
|
+
3. 验证事件监听器是否已注册
|
|
526
|
+
|
|
527
|
+
### 初始化消息未发送
|
|
528
|
+
|
|
529
|
+
1. 确认 `autoInit` 为 `true`
|
|
530
|
+
2. 检查组件是否已完全渲染
|
|
531
|
+
3. 查看控制台是否有错误
|
|
532
|
+
|
|
533
|
+
## 示例
|
|
534
|
+
|
|
535
|
+
完整示例请参考 Storybook 中的 `WebViewBridge` 组件示例。
|
|
536
|
+
|