# XWebView `@xuqm/rn-xwebview` 提供可直接打开的独立 WebView 页面,也支持在业务页面中嵌入浏览器 内核。SDK 只提供通用容器和 Bridge 接入入口,不内置任何宿主业务协议。 ## 安装 ```bash pnpm add @xuqm/rn-common @xuqm/rn-xwebview \ react-native-webview react-native-svg \ @react-native-clipboard/clipboard react-native-safe-area-context ``` 这些原生依赖需要由宿主直接声明,以便 React Native 自动链接。 ## 根部挂载 Host 独立页面模式需要在应用根部挂载一次: ```tsx import { XWebViewHost } from '@xuqm/rn-xwebview' export function App() { return ( <> ) } ``` 全局只能存在一个 `XWebViewHost`。 ## 打开独立页面 ```ts import { openWebView } from '@xuqm/rn-xwebview' const page = openWebView({ source: { uri: 'https://example.com', headers: { 'X-From-App': 'true', }, }, navigationBar: { title: { text: '服务页面', mode: 'web', }, }, statusBar: { translucent: true, contentStyle: 'dark-content', }, }) const result = await page.closed console.log(result.reason, result.data) ``` 返回的页面 Handle 可以: ```ts page.reload() page.goBack() page.goForward() page.postMessage(JSON.stringify({ type: 'refresh' })) page.evaluateJavaScript('window.refreshPage?.()') page.suspend() page.resume() page.close('api', { completed: true }) ``` `suspend()` 用于临时展示宿主原生页面,页面实例和网页历史会保留;完成后调用 `resume()`。 ## 默认导航和返回规则 - 左上角返回按钮只在当前网页存在历史页面时显示,只负责网页后退。 - 右上角关闭按钮始终显示,点击立即关闭当前 WebView 页面。 - Android 物理返回键优先返回网页历史。 - 没有网页历史时,物理返回键需要在一秒内再次按下才关闭页面。 - 默认菜单包含刷新、复制链接和在系统浏览器打开,不包含关闭页面。 ## 导航栏与状态栏 ```ts openWebView({ source: { uri: 'https://example.com' }, navigationBar: { background: { gradient: ['#1769E0', '#55A8FF'], gradientAngle: 90, // 也可以使用 color 或 image }, title: { text: '渐变导航栏', color: '#FFFFFF', mode: 'fixed', }, backButton: { color: '#FFFFFF' }, closeButton: { color: '#FFFFFF' }, }, statusBar: { backgroundColor: '#1769E0', contentStyle: 'light-content', translucent: true, }, }) ``` 网络背景图片异步加载,不会阻塞 `openWebView` 返回。 完整替换导航栏时使用 `navigationBar.render(context)`。自定义返回按钮应调用 `context.onBackPress()`,以保留统一的网页后退规则。 ## 自定义菜单 ```tsx openWebView({ source: { uri: 'https://example.com' }, navigationBar: { menu: { visible: true, items: [ { id: 'feedback', label: '问题反馈', onPress({ navigationState }) { openFeedback({ url: navigationState.url }) }, }, ], }, }, }) ``` 不需要菜单时设置 `menu.visible: false`。 ## 摄像头和麦克风 宿主先声明系统权限,然后为具体网页配置精确 Origin: ```ts openWebView({ source: { uri: 'https://verify.example.com/start' }, permissions: { allowedOrigins: ['https://verify.example.com'], camera: true, microphone: true, }, }) ``` Android Manifest 示例: ```xml ``` Origin 必须包含协议和主机,跨域后的页面不会继承原页面授权。宿主需要自定义决策时: ```ts permissions: { allowedOrigins: ['https://verify.example.com'], camera: true, microphone: true, onRequest(request) { if (canUseMedia(request.origin)) request.grant() else request.deny() }, } ``` ## 文件下载 ```ts openWebView({ source: { uri: 'https://example.com/files' }, downloads: { auto: true, destination: 'publicDownloads', conflict: 'rename', onProgress(progress) { console.log(progress.percentage) }, onComplete(result) { console.log(result.filePath) }, onError(url, error) { console.warn(url, error) }, }, }) ``` 默认保存到应用沙盒。保存到系统 Downloads 只在目标平台支持时生效。 ## 宿主 Bridge 宿主与 H5 自行约定消息协议,通过 `bridge` 注入: ```ts openWebView({ source: { uri: 'https://example.com' }, bridge: { async onMessage(raw, context) { const message = JSON.parse(raw) if (message.method === 'close') { context.close('h5_close', message.data) return true } if (message.method === 'setTitle') { context.updateNavigation({ title: { text: String(message.title ?? '') }, }) return true } return false }, }, }) ``` XWebView 不规定方法名、App ID、厂商、用户或业务参数。协议校验、权限和业务结果由宿主 自己的 Bridge 负责。 ## 内嵌 WebView 不需要独立页面和内置导航栏时: ```tsx import { XWebViewView } from '@xuqm/rn-xwebview' ``` 内嵌模式由所在页面负责尺寸、导航和关闭交互。