You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native WebView无法打开Blob URL下载PDF问题求助

解决React Native WebView中Blob URL的PDF下载问题

问题根源

Blob URL是WebView内部上下文生成的,仅在当前WebView会话中有效,RN原生层无法直接访问这类URL,所以fetch请求会失败;而WebView默认的导航逻辑不支持Blob URL跳转,导致点击下载按钮无响应。

可行方案:通过JS注入拦截Blob数据并传递给RN原生处理

核心思路是在网页中注入脚本,监听PDF生成/下载流程,将Blob数据转换成base64格式后发送给RN端,再由RN原生代码处理保存或打开操作。

1. 配置WebView,注入监听脚本

import React, { useRef } from 'react';
import { WebView } from 'react-native-webview';

const PDFWebView = () => {
  const webViewRef = useRef(null);

  // 注入JS:拦截Blob创建,转base64后发送给RN
  const injectScript = `
    // 重写Blob构造函数,拦截PDF类型的Blob
    const originalBlob = window.Blob;
    window.Blob = function(parts, options) {
      const blob = new originalBlob(parts, options);
      if (options?.type === 'application/pdf') {
        const reader = new FileReader();
        reader.onloadend = function() {
          window.ReactNativeWebView.postMessage(JSON.stringify({
            type: 'PDF_BLOB',
            data: reader.result,
            filename: 'document.pdf' // 可根据网页逻辑动态替换文件名
          }));
        };
        reader.readAsDataURL(blob);
      }
      return blob;
    };

    // 可选:直接监听下载按钮点击(如果知道按钮选择器)
    const downloadBtn = document.querySelector('#pdf-download-btn');
    if (downloadBtn) {
      downloadBtn.addEventListener('click', e => e.preventDefault());
    }
  `;

  // 接收WebView传来的消息
  const handleMessage = (event) => {
    const message = JSON.parse(event.nativeEvent.data);
    if (message.type === 'PDF_BLOB') {
      handlePDFDownload(message.data, message.filename);
    }
  };

  return (
    <WebView
      ref={webViewRef}
      source={{ uri: '你的目标网页URL' }}
      injectedJavaScript={injectScript}
      onMessage={handleMessage}
      javaScriptEnabled={true}
      domStorageEnabled={true}
    />
  );
};

export default PDFWebView;

2. RN端处理base64数据,保存为本地PDF

以react-native-fs库为例(先安装:npm install react-native-fs --save并完成原生链接):

import RNFS from 'react-native-fs';

const handlePDFDownload = async (base64Data, filename) => {
  try {
    // 移除base64前缀(data:application/pdf;base64,)
    const pureBase64 = base64Data.split(',')[1];
    // 指定存储路径(Documents目录)
    const filePath = `${RNFS.DocumentDirectoryPath}/${filename}`;
    
    // 写入文件
    await RNFS.writeFile(filePath, pureBase64, 'base64');
    
    console.log('PDF保存成功,路径:', filePath);
    // 可选:用react-native-pdf等库打开预览
  } catch (error) {
    console.error('保存PDF失败:', error);
  }
};

3. 替代方案:拦截Blob URL导航请求

如果下载按钮是直接跳转Blob URL,可通过拦截导航事件获取数据:

const handleShouldStartLoadWithRequest = (request) => {
  if (request.url.startsWith('blob:')) {
    // 注入JS获取该Blob URL对应的Blob数据
    webViewRef.current.injectJavaScript(`
      fetch('${request.url}')
        .then(res => res.blob())
        .then(blob => {
          const reader = new FileReader();
          reader.onloadend = () => {
            window.ReactNativeWebView.postMessage(JSON.stringify({
              type: 'PDF_BLOB',
              data: reader.result,
              filename: 'document.pdf'
            }));
          };
          reader.readAsDataURL(blob);
        });
    `);
    // 阻止WebView默认跳转
    return false;
  }
  return true;
};

// 在WebView中添加该属性
<WebView
  ...
  shouldStartLoadWithRequest={handleShouldStartLoadWithRequest}
/>

注意事项

  • 若网页Blob生成逻辑复杂,需调整注入脚本确保精准拦截目标PDF的Blob。
  • 大体积PDF使用base64可能有性能问题,可考虑分块处理或传递ArrayBuffer(需额外处理RN端接收逻辑)。
  • 保存后如需预览,可使用react-native-pdf或expo-document-picker等库实现。

内容的提问来源于stack exchange,提问作者rluyckx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:37:17