T-B01: XuqmBundleModule 原生模块 - Android: XuqmBundleModule.java(文件读写/manifest/路径) - iOS: XuqmBundleModule.m(对应实现) - JS: NativeBundle.ts 封装 - 注册到 XuqmUpdatePackage T-B02: downloadPluginBundle 添加 onProgress - 使用 ReadableStream 实现下载进度追踪 - checkAndCachePlugin 同步支持 onProgress T-B03: XWebView JSBridge 标准接口文档 - docs/XWebView-JSBridge.md - H5→RN 消息协议 / RN→H5 通信 - 下载处理 / Dialog 覆盖 / 标准 Bridge 接口 T-B04: PushSDK Android 厂商集成文档 - docs/PushSDK-厂商集成.md - 6 厂商配置步骤 / ProGuard 规则 / 调试指南
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);
|
||
});
|
||
```
|