React Native WebView场景下下载zip文件的实现问题咨询
React Native WebView下载Aadhaar离线KYC zip文件解决方案
你之前直接调用API失败的核心原因是缺少WebView内的会话Cookie、请求头校验参数,该站点做了同源校验,直接请求会被拦截,可通过以下两种方案解决:
方案1:启用WebView原生下载回调+会话凭证同步
你注释的onFileDownload是安卓端的核心入口,iOS需要额外通过请求拦截处理,具体实现如下:
- 修正WebView基础配置
<WebView source={{ uri: "https://resident.uidai.gov.in/offline-kyc" }} ref={webviewRef} renderLoading={LoadingIndicatorView} startInLoadingState={true} injectedJavaScript={runFirst} onMessage={onMessage} renderError={loadError} allowFileAccess={true} allowFileAccessFromFileURLs={true} javaScriptEnabled={true} domStorageEnabled={true} // 安卓端下载回调 onFileDownload={async ({ nativeEvent: { downloadUrl } }) => { // 同步WebView当前会话Cookie,避免请求无权限 const cookie = await webviewRef.current.injectJavaScript("document.cookie;"); const userAgent = await webviewRef.current.injectJavaScript("navigator.userAgent;"); downloadFile(downloadUrl, cookie, userAgent); }} // iOS端拦截下载请求 shouldStartLoadWithRequest={(request) => { if (request.url.endsWith('.zip') || request.headers['Content-Type'] === 'application/zip') { downloadFile(request.url, request.headers['Cookie'], request.headers['User-Agent']); // 拦截下载请求,不让WebView默认处理 return false; } return true; }} />
- 实现文件下载逻辑,推荐搭配
rn-fetch-blob处理文件写入,请求头保持和WebView一致,避免站点反爬拦截
import RNFetchBlob from 'rn-fetch-blob'; const downloadFile = async (url, cookie, userAgent) => { const { dirs } = RNFetchBlob.fs; const config = { fileCache: true, addAndroidDownloads : { useDownloadManager : true, notification : true, path: `${dirs.DownloadDir}/aadhaar_offline_kyc.zip`, description : 'Aadhaar离线KYC文件下载', mime: 'application/zip' }, headers: { 'Cookie': cookie, 'Referer': 'https://resident.uidai.gov.in/offline-kyc', 'User-Agent': userAgent } }; RNFetchBlob.config(config) .fetch('GET', url) .then(res => { console.log('文件下载完成,路径:', res.path()); }) .catch(err => console.log('下载失败:', err)); }
方案2:注入JS监听Blob类型下载(适配iOS端blob流下载场景)
如果站点是通过JS生成Blob对象触发下载,没有公开的直链,可通过注入JS拦截下载行为,把Blob转成base64传给RN端写入本地:
- 注入JS代码扩展原有的自动点击逻辑
const runFirst = ` // 拦截a标签下载行为 const originalClick = HTMLAnchorElement.prototype.click; HTMLAnchorElement.prototype.click = function() { if (this.download && this.href.includes('blob:')) { fetch(this.href) .then(res => res.blob()) .then(blob => { const reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = () => { window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'download', data: reader.result, filename: this.download })); } }) return; } originalClick.call(this); } // 原有自动点击提交按钮逻辑 // ... true; `;
- 处理onMessage回调写入本地文件
const onMessage = (event) => { const data = JSON.parse(event.nativeEvent.data); if (data.type === 'download') { const base64Code = data.data.split(',')[1]; RNFetchBlob.fs.writeFile( `${RNFetchBlob.fs.dirs.DownloadDir}/${data.filename}`, base64Code, 'base64' ).then(() => console.log('文件写入成功')); } }
内容的提问来源于stack exchange,提问作者Abhay
相关产品推荐
相关产品推荐

