212 行
5.9 KiB
Markdown
212 行
5.9 KiB
Markdown
|
|
# XWebView JSBridge 标准接口
|
|||
|
|
|
|||
|
|
> 最后更新:2026-06-15
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
XWebView 内置 JSBridge,支持 H5 页面与 React Native 宿主之间的双向通信。
|
|||
|
|
|
|||
|
|
**通信机制**:
|
|||
|
|
- H5 → RN:`window.ReactNativeWebView.postMessage(JSON.stringify(data))`
|
|||
|
|
- RN → H5:`webViewRef.injectJavaScript(jsString)`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、H5 → RN 消息协议
|
|||
|
|
|
|||
|
|
### 1.1 内置消息(__xwv 前缀)
|
|||
|
|
|
|||
|
|
XWebView 自动拦截以下浏览器行为,通过 `postMessage` 发送给 RN:
|
|||
|
|
|
|||
|
|
| 消息类型 | 触发场景 | 数据格式 |
|
|||
|
|
|---------|---------|---------|
|
|||
|
|
| `alert` | `window.alert(msg)` | `{__xwv: 'alert', msg: string}` |
|
|||
|
|
| `confirm` | `window.confirm(msg)` | `{__xwv: 'confirm', msg: string}` |
|
|||
|
|
| `prompt` | `window.prompt(msg, def)` | `{__xwv: 'prompt', msg: string, def: string}` |
|
|||
|
|
| `download` | 点击下载链接 | `{__xwv: 'download', url: string, filename: string}` |
|
|||
|
|
| `blobdownload` | blob URL 下载 | `{__xwv: 'blobdownload', url: string, filename: string, data: base64}` |
|
|||
|
|
| `bloberror` | blob 读取失败 | `{__xwv: 'bloberror', msg: string}` |
|
|||
|
|
| `log` | 调试日志 | `{__xwv: 'log', msg: string}` |
|
|||
|
|
|
|||
|
|
### 1.2 自定义消息
|
|||
|
|
|
|||
|
|
H5 发送非 `__xwv` 前缀的消息时,XWebView 将其转发给 `onMessage` 回调:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// H5 端
|
|||
|
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|||
|
|
type: 'customEvent',
|
|||
|
|
payload: { key: 'value' }
|
|||
|
|
}));
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// RN 端
|
|||
|
|
<XWebViewView
|
|||
|
|
onMessage={(event) => {
|
|||
|
|
const data = JSON.parse(event.nativeEvent.data);
|
|||
|
|
if (data.type === 'customEvent') {
|
|||
|
|
// 处理自定义消息
|
|||
|
|
}
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、RN → H5 通信
|
|||
|
|
|
|||
|
|
### 2.1 注入 JavaScript
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 通过 controller API
|
|||
|
|
controller.postMessageToWeb('window.dispatchEvent(new CustomEvent("rnMessage", {detail: {type: "update", data: "hello"}}))');
|
|||
|
|
|
|||
|
|
// 通过 ref
|
|||
|
|
webViewRef.injectJavaScript('window.handleRNMessage("hello")');
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 Controller API
|
|||
|
|
|
|||
|
|
通过 `setXWebViewController` 获取的 controller 对象提供以下方法:
|
|||
|
|
|
|||
|
|
| 方法 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| `refresh()` | 刷新当前页面 |
|
|||
|
|
| `close()` | 关闭 WebView |
|
|||
|
|
| `goBack()` | 返回上一页 |
|
|||
|
|
| `goForward()` | 前进 |
|
|||
|
|
| `copyUrl()` | 复制当前 URL 到剪贴板 |
|
|||
|
|
| `postMessageToWeb(jsString)` | 向 H5 注入并执行 JS |
|
|||
|
|
| `getTitle()` | 获取当前页面标题 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、下载处理
|
|||
|
|
|
|||
|
|
### 3.1 自动下载拦截
|
|||
|
|
|
|||
|
|
XWebView 自动拦截以下文件扩展名的链接点击:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
.pdf .zip .rar .tar .gz .apk .ipa .doc .docx .xls .xlsx .ppt .pptx .mp4 .mp3 .mov .exe .dmg
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 下载回调
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
<XWebViewView
|
|||
|
|
autoDownload={true}
|
|||
|
|
onDownloadStart={(request) => {
|
|||
|
|
// request: { url, suggestedFilename, mimeType?, fileSize? }
|
|||
|
|
console.log('Download started:', request.suggestedFilename);
|
|||
|
|
}}
|
|||
|
|
onDownloadProgress={(progress) => {
|
|||
|
|
// progress: { url, filename, received, total, percentage }
|
|||
|
|
console.log(`Download: ${progress.percentage}%`);
|
|||
|
|
}}
|
|||
|
|
onDownloadComplete={(result) => {
|
|||
|
|
// result: { url, filename, filePath, fileSize }
|
|||
|
|
console.log('Download complete:', result.filePath);
|
|||
|
|
}}
|
|||
|
|
onDownloadError={(url, error) => {
|
|||
|
|
console.error('Download failed:', url, error);
|
|||
|
|
}}
|
|||
|
|
onDownloadDecide={(request) => {
|
|||
|
|
// 返回下载决策
|
|||
|
|
return { allowed: true, filename: request.suggestedFilename };
|
|||
|
|
}}
|
|||
|
|
downloadConflict="rename" // 'rename' | 'overwrite'
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 Blob URL 下载
|
|||
|
|
|
|||
|
|
XWebView 自动处理 blob URL 下载:
|
|||
|
|
1. 拦截 `<a href="blob:...">` 点击
|
|||
|
|
2. 通过 `FileReader` 读取 blob 数据为 base64
|
|||
|
|
3. 通过 `saveBase64File` 保存到本地
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、内置 Dialog 覆盖
|
|||
|
|
|
|||
|
|
XWebView 注入 `DIALOG_OVERRIDE_JS`,覆盖浏览器原生对话框:
|
|||
|
|
|
|||
|
|
| 原生方法 | 覆盖行为 |
|
|||
|
|
|---------|---------|
|
|||
|
|
| `window.alert(msg)` | 发送 `{__xwv: 'alert', msg}` 消息 |
|
|||
|
|
| `window.confirm(msg)` | 发送 `{__xwv: 'confirm', msg}` 消息,始终返回 `true` |
|
|||
|
|
| `window.prompt(msg, def)` | 发送 `{__xwv: 'prompt', msg, def}` 消息,返回默认值 |
|
|||
|
|
| `window.open(url)` | 发送日志消息,然后 `window.location.href = url` |
|
|||
|
|
|
|||
|
|
RN 端收到这些消息后,可以展示原生 Alert/Confirm/Prompt 对话框。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、标准 Bridge 接口(宿主实现)
|
|||
|
|
|
|||
|
|
以下接口由宿主应用通过 `bridgeHandlers` 实现,H5 通过 `xuqm.call(method, params)` 调用:
|
|||
|
|
|
|||
|
|
### 5.1 会话管理
|
|||
|
|
|
|||
|
|
| 接口 | 参数 | 返回值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `getSession` | — | `{token, userId}` | 获取当前登录会话 |
|
|||
|
|
| `getUserInfo` | — | `{userId, name, phone, avatar}` | 获取用户信息 |
|
|||
|
|
|
|||
|
|
### 5.2 导航
|
|||
|
|
|
|||
|
|
| 接口 | 参数 | 返回值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `navigate` | `{screen, params?}` | — | 跳转宿主页面 |
|
|||
|
|
| `close` | — | — | 关闭当前 WebView |
|
|||
|
|
| `goBack` | — | — | 返回上一页 |
|
|||
|
|
|
|||
|
|
### 5.2 UI 交互
|
|||
|
|
|
|||
|
|
| 接口 | 参数 | 返回值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `showToast` | `{message}` | — | 显示 Toast |
|
|||
|
|
| `showAlert` | `{title?, message}` | — | 显示 Alert 对话框 |
|
|||
|
|
| `showConfirm` | `{title?, message, confirmText?, cancelText?}` | `{confirmed: boolean}` | 显示确认对话框 |
|
|||
|
|
|
|||
|
|
### 5.3 文件操作
|
|||
|
|
|
|||
|
|
| 接口 | 参数 | 返回值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `uploadFile` | `{accept?}` | `{url, name, size}` | 选择并上传文件 |
|
|||
|
|
| `openCamera` | — | `{url, base64}` | 打开相机拍照 |
|
|||
|
|
| `scanQR` | — | `{result}` | 扫描二维码 |
|
|||
|
|
|
|||
|
|
### 5.4 设备信息
|
|||
|
|
|
|||
|
|
| 接口 | 参数 | 返回值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| `getDeviceInfo` | — | `{platform, version, model}` | 获取设备信息 |
|
|||
|
|
| `getLocation` | — | `{latitude, longitude}` | 获取当前位置 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、H5 端调用示例
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// 获取会话
|
|||
|
|
xuqm.call('getSession').then(session => {
|
|||
|
|
console.log('Token:', session.token);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 跳转宿主页面
|
|||
|
|
xuqm.call('navigate', { screen: 'Settings' });
|
|||
|
|
|
|||
|
|
// 显示 Toast
|
|||
|
|
xuqm.call('showToast', { message: '操作成功' });
|
|||
|
|
|
|||
|
|
// 上传文件
|
|||
|
|
xuqm.call('uploadFile', { accept: 'image/*' }).then(file => {
|
|||
|
|
console.log('Uploaded:', file.url);
|
|||
|
|
});
|
|||
|
|
```
|