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

Flutter中ipfs_http_rpc与flutter_ipfs文件上传问题求助

Flutter 上传文件到 IPFS 解决方案

问题根源

  1. Web 平台下 file_picker 的 path 字段始终为 null,必须通过 bytes 获取文件二进制数据
  2. 错误使用 IPFS 包参数:ipfs_http_rpc 的 add 方法混淆了 path(本地文件路径)与 content(二进制数据)参数;flutter_ipfs 要求传入的字符串必须是Base64编码的二进制数据,而非直接将 byte 转成字符串列表

针对 ipfs_http_rpc 的修复方案

该包的 add 方法支持直接传入二进制数据,只需将参数从 path 改为 content:

// 修正后的核心代码片段
if (result != null) {
  List<int> fileBytes = result.files.first.bytes!;
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) => ProgressDialog(status: 'Uploading to IPFS'),
  );
  Ipfs ipfs = Ipfs();
  // 使用 content 参数传入二进制数据
  Map<String, dynamic> response = await ipfs.add(content: fileBytes, wrapWithDirectory: true);
  // 正确获取IPFS返回的CID
  cid = response['Hash'] as String;
  debugPrint(cid);

  Navigator.pop(context);
  return cid;
}

针对 flutter_ipfs 的修复方案

将二进制数据转为 Base64 编码字符串后传入,因为该包的 uploadToIpfs 方法实际期望接收的是 Base64 格式的二进制内容:

import 'dart:convert'; // 导入Base64编码工具

// 修正后的核心代码片段
if (result != null) {
  List<int> bytesList = result.files.first.bytes!;
  // 将二进制数据转为Base64字符串
  String base64Content = base64Encode(bytesList);
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) => ProgressDialog(status: 'Uploading to IPFS'),
  );

  cid = await FlutterIpfs().uploadToIpfs(base64Content);
  debugPrint(cid);

  Navigator.pop(context);
  return cid;
}

完整修正后的 PdfPickerService 示例(以 ipfs_http_rpc 为例)

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:ipfs_http_rpc/ipfs.dart';

class PdfPickerService {
  static String cid = "";

  static Future<String?> pickPdf(BuildContext context) async {
    try {
      FilePickerResult? result = await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowedExtensions: ['pdf'],
      );

      if (result != null) {
        List<int> fileBytes = result.files.first.bytes!;
        showDialog(
          barrierDismissible: false,
          context: context,
          builder: (BuildContext context) => const ProgressDialog(status: 'Uploading to IPFS'),
        );

        Ipfs ipfs = Ipfs();
        // 可指定线上IPFS节点,默认是本地节点http://127.0.0.1:5001
        // Ipfs ipfs = Ipfs(ipfsApi: 'https://your-ipfs-gateway.com/api/v0');
        Map<String, dynamic> response = await ipfs.add(content: fileBytes, wrapWithDirectory: true);
        cid = response['Hash'] as String;
        debugPrint("Uploaded CID: $cid");

        Navigator.pop(context);
        Fluttertoast.showToast(msg: '文件上传成功');
        return cid;
      } else {
        Fluttertoast.showToast(msg: '未选择PDF文件');
        return null;
      }
    } catch (e) {
      debugPrint('PDF选择/上传错误: $e');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            '错误: $e',
            textAlign: TextAlign.center,
            style: const TextStyle(fontSize: 15),
          ),
        ),
      );
      return null;
    }
  }
}

// 配套的ProgressDialog组件示例
class ProgressDialog extends StatelessWidget {
  final String status;
  const ProgressDialog({super.key, required this.status});

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      content: Row(
        children: [
          const CircularProgressIndicator(),
          const SizedBox(width: 16),
          Text(status),
        ],
      ),
    );
  }
}

关键注意点

  • IPFS节点访问:如果使用本地IPFS节点,需确保节点已启动;使用线上节点要在初始化 Ipfs 时指定正确的API地址
  • 数据完整性:直接将 byte 转成数字字符串会导致数据损坏,Base64是二进制转字符串的标准兼容方案
  • 错误处理优化:补充了SnackBar的正确调用逻辑,确保错误信息能正常展示给用户

内容的提问来源于stack exchange,提问作者abdullah bin sajjad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:15:57