XuqmGroup-Web/docs-site/docs/rn/xwebview.md
2026-07-29 02:43:17 +08:00

5.4 KiB

XWebView

@xuqm/rn-xwebview 提供可直接打开的独立 WebView 页面,也支持在业务页面中嵌入浏览器 内核。SDK 只提供通用容器和 Bridge 接入入口,不内置任何宿主业务协议。

安装

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

独立页面模式需要在应用根部挂载一次:

import { XWebViewHost } from '@xuqm/rn-xwebview'

export function App() {
  return (
    <>
      <RootNavigation />
      <XWebViewHost />
    </>
  )
}

全局只能存在一个 XWebViewHost

打开独立页面

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 可以:

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 物理返回键优先返回网页历史。
  • 没有网页历史时,物理返回键需要在一秒内再次按下才关闭页面。
  • 默认菜单包含刷新、复制链接和在系统浏览器打开,不包含关闭页面。

导航栏与状态栏

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(),以保留统一的网页后退规则。

自定义菜单

openWebView({
  source: { uri: 'https://example.com' },
  navigationBar: {
    menu: {
      visible: true,
      items: [
        {
          id: 'feedback',
          label: '问题反馈',
          onPress({ navigationState }) {
            openFeedback({ url: navigationState.url })
          },
        },
      ],
    },
  },
})

不需要菜单时设置 menu.visible: false

摄像头和麦克风

宿主先声明系统权限,然后为具体网页配置精确 Origin

openWebView({
  source: { uri: 'https://verify.example.com/start' },
  permissions: {
    allowedOrigins: ['https://verify.example.com'],
    camera: true,
    microphone: true,
  },
})

Android Manifest 示例:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Origin 必须包含协议和主机,跨域后的页面不会继承原页面授权。宿主需要自定义决策时:

permissions: {
  allowedOrigins: ['https://verify.example.com'],
  camera: true,
  microphone: true,
  onRequest(request) {
    if (canUseMedia(request.origin)) request.grant()
    else request.deny()
  },
}

文件下载

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 注入:

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

不需要独立页面和内置导航栏时:

import { XWebViewView } from '@xuqm/rn-xwebview'

<XWebViewView
  config={{
    source: { uri: 'https://example.com' },
  }}
/>

内嵌模式由所在页面负责尺寸、导航和关闭交互。