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
相关产品推荐
相关产品推荐

