如何从Blob URL下载图片?已尝试多方案无效求解决
解决Flutter中Blob URL图片下载的问题
我之前也踩过这个坑,Blob URL是WebView内部生成的临时地址,只在当前WebView的会话中有效,直接用Flutter的http.get去请求肯定会失败——因为这个URL不是标准的HTTP/HTTPS地址,原生的网络客户端根本无法解析它。下面给你两个可行的解决方案:
方案一:通过WebView JS交互获取Blob的Base64数据
这个方法的核心是在WebView中注入JavaScript脚本,把Blob转换成Base64格式,再通过JS通道传递给Flutter原生,最后保存成文件。
步骤1:配置WebView并注入JS脚本
假设你用的是webview_flutter包,初始化WebView时添加JS消息监听和注入脚本:
import 'dart:convert'; import 'dart:typed_data'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:io'; late WebViewController _webViewController; @override Widget build(BuildContext context) { return WebView( initialUrl: "你的网页地址", javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (controller) { _webViewController = controller; // 注入JS脚本,监听图片下载事件(这里假设网页里有下载按钮,id为downloadBtn) _webViewController.runJavascript(''' document.getElementById('downloadBtn').addEventListener('click', async () => { const blobUrl = '你的Blob图片URL'; // 或者从网页DOM中获取实际的Blob URL const response = await fetch(blobUrl); const blob = await response.blob(); const reader = new FileReader(); reader.onloadend = function() { // 把Base64数据发送给Flutter window.flutter_inappwebview.callHandler('saveImage', reader.result); }; reader.readAsDataURL(blob); }); '''); }, javascriptChannels: { JavascriptChannel( name: 'saveImage', onMessageReceived: (JavascriptMessage message) { // 处理从JS传来的Base64数据 _saveImageFromBase64(message.message); }, ), }, ); }
步骤2:Flutter端解析Base64并保存文件
Future<void> _saveImageFromBase64(String base64Data) async { // 去除Base64前缀(比如data:image/png;base64,) final pureBase64 = base64Data.replaceFirst(RegExp(r'data:image/[^;]+;base64,'), ''); final bytes = base64Decode(pureBase64); final documentDir = await getApplicationDocumentsDirectory(); final file = File('${documentDir.path}/downloaded_image.png'); await file.writeAsBytes(bytes); // 这里可以添加下载成功的提示逻辑 print('图片已保存到:${file.path}'); }
方案二:拦截WebView的下载请求(适用于自动触发的下载)
如果网页是自动触发Blob下载(比如点击后直接发起下载请求),可以通过WebView的下载拦截回调来处理:
WebView( // ...其他基础配置 onDownloadStart: (downloadUrl) async { // 判断是否是Blob URL if (downloadUrl.startsWith('blob:')) { // 通过JS获取Blob对应的Base64数据 final base64Data = await _webViewController.runJavascriptReturningResult(''' (async () => { const response = await fetch('$downloadUrl'); const blob = await response.blob(); const reader = new FileReader(); return new Promise((resolve) => { reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); })(); '''); // 去除返回结果的引号包裹 final cleanBase64 = base64Data.replaceAll('"', ''); await _saveImageFromBase64(cleanBase64); } }, )
为什么你之前的代码无效?
你用http.get直接请求Blob URL,这个URL是WebView内部的临时标识,只有WebView的浏览器内核能识别它对应的Blob数据,Flutter的原生HTTP客户端(比如dart:io的HttpClient或者http包)无法解析blob:协议,自然会请求失败。
内容的提问来源于stack exchange,提问作者Velliane
相关产品推荐
相关产品推荐

