React Native WebView中Base64格式图片下载实现求助
解决WebView中Base64格式图片无法通过download标签下载的问题
WebView对data URI的download属性支持存在局限性,默认不会触发下载流程,需要通过平台端拦截处理或前端预处理来解决,以下是具体方案:
一、Android WebView 拦截处理
通过自定义下载监听器识别Base64链接,手动解码并写入本地文件:
webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> { if (url.startsWith("data:")) { // 拆分data URI结构 String[] uriParts = url.split(","); String metaInfo = uriParts[0]; String base64Content = uriParts[1]; // 提取文件类型与后缀 String mimeTypeFull = metaInfo.split(";")[0].replace("data:", ""); String fileExt = mimeTypeFull.split("/")[1]; // 解码Base64为字节流 byte[] fileBytes = Base64.decode(base64Content, Base64.DEFAULT); // 写入本地下载目录 File saveFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "download." + fileExt); try (FileOutputStream fos = new FileOutputStream(saveFile)) { fos.write(fileBytes); // 通知系统扫描文件,使其在相册/下载列表中可见 MediaScannerConnection.scanFile(this, new String[]{saveFile.getAbsolutePath()}, null, null); } catch (IOException e) { e.printStackTrace(); } } else { // 保留原有普通URL下载逻辑 } });
注意:需提前申请WRITE_EXTERNAL_STORAGE权限(Android 13+需申请READ_MEDIA_IMAGES等细分权限)。
二、iOS WKWebView 拦截处理
通过导航代理拦截data URI请求,解析后转为Data保存到本地:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let requestUrl = navigationAction.request.url, requestUrl.scheme == "data" else { decisionHandler(.allow) return } let uriComponents = requestUrl.absoluteString.split(separator: ",") guard uriComponents.count == 2, let metaSection = uriComponents.first, let base64Section = uriComponents.last else { decisionHandler(.allow) return } // 提取MIME类型与文件后缀 let metaParts = metaSection.split(separator: ";") guard let mimeTypePart = metaParts.first, mimeTypePart.starts(with: "data:"), let fileExt = mimeTypePart.dropFirst(5).split(separator: "/").last else { decisionHandler(.allow) return } // 解码并保存文件 if let fileData = Data(base64Encoded: String(base64Section)) { let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let saveUrl = docDir.appendingPathComponent("download.\(fileExt)") do { try fileData.write(to: saveUrl) // 可添加通知提示用户下载完成,或调用系统打开文件 } catch { print("文件保存失败:\(error.localizedDescription)") } } decisionHandler(.cancel) // 取消原请求,避免WebView无效处理 }
注意:需在Info.plist中配置文件访问相关权限,若需共享文件到系统相册,还需额外处理相册写入权限。
三、前端通用预处理方案
通过JavaScript监听点击事件,将Base64转为Blob后触发下载,适配多平台WebView:
document.addEventListener('click', function(e) { const targetLink = e.target.closest('a'); if (!targetLink || !targetLink.href.startsWith('data:')) return; e.preventDefault(); // 阻止默认下载行为 // 解析data URI const [metaStr, base64Str] = targetLink.href.split(','); const mimeType = metaStr.split(';')[0].replace('data:', ''); // Base64转Blob const byteChars = atob(base64Str); const byteNumbers = new Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteNumbers[i] = byteChars.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const fileBlob = new Blob([byteArray], { type: mimeType }); // 创建临时URL触发下载 const tempUrl = URL.createObjectURL(fileBlob); const downloadLink = document.createElement('a'); downloadLink.href = tempUrl; downloadLink.download = targetLink.download || `download.${mimeType.split('/')[1]}`; document.body.appendChild(downloadLink); downloadLink.click(); // 清理临时资源 setTimeout(() => { URL.revokeObjectURL(tempUrl); document.body.removeChild(downloadLink); }, 100); });
注意:需确保WebView开启JavaScript支持(Android需设置webSettings.setJavaScriptEnabled(true),iOS默认开启)。
内容的提问来源于stack exchange,提问作者rafiulah
相关产品推荐
相关产品推荐

