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

如何从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:06:50