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

Flutter中FirebaseStorage的Reference无exists方法报错求助

Flutter FirebaseStorage 报错:The method 'exists' isn't defined for the type 'Reference'

问题说明

在Flutter项目中删除Firebase数据库关联的存储文件时,触发上述错误,问题出在检查文件是否存在的代码行:

bool exists = await FirebaseStorage.instance.ref(ref).exists();

核心原因是FirebaseStorage的Reference类并没有提供exists()方法,需要改用官方推荐的方式判断文件状态。

相关代码片段

构建文件引用路径的代码:

String ref = _selectedRef!;

if (!ref.startsWith("/")) {
  ref = "/" + ref;
}

ref = ref.substring(0, ref.lastIndexOf("/") + 1) + ".pdf"; 

原判断逻辑代码:

if (exists) {
  await FirebaseStorage.instance.ref(ref).delete();
  await FirebaseFirestore.instance
      .collection("file")
      .where("ref", isEqualTo: _selectedRef)
      .get()
      .then((snapshot) {
    snapshot.docs.first.reference.delete();
  });
  setState(() {
    _selectedRef = null;
  });
} else {
  ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text("选中的文件不存在")));
}

解决方案

FirebaseStorage判断文件是否存在的正确方式是调用getMetadata()方法,通过捕获异常来判定:

  • 文件存在时,getMetadata()会正常返回元数据
  • 文件不存在时,会抛出FirebaseException异常(错误码为object-not-found)

修改deleteFirebaseData()方法中的检查逻辑:

// 替换原有的exists()调用
bool exists = true;
try {
  await FirebaseStorage.instance.ref(ref).getMetadata();
} on FirebaseException catch (e) {
  if (e.code == 'object-not-found') {
    exists = false;
  }
}

完整修正后的代码

import 'dart:io';
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'package:fimprac/screen_acercade.dart';
import 'package:fimprac/screen_home.dart';
import 'package:fimprac/main.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/material/navigation_drawer.dart';
import 'package:fimprac/menu.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';

main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    home: perfilSC(),
  ));
}

class perfilSC extends StatefulWidget {
  const perfilSC({super.key});

  @override
  State<perfilSC> createState() => _perfilSCState();
}

class _perfilSCState extends State<perfilSC> {
  String? _selectedRef; // 存储选中文件的引用
  String url = "";
  int? number;
  late QueryDocumentSnapshot selectedSnapshot;

  uploadDataToFirebase() async {
    // 生成随机数
    number = Random().nextInt(10);
    // 选择PDF文件
    FilePickerResult? result = await FilePicker.platform.pickFiles();
    File pick = File(result!.files.single.path.toString());
    var file = pick.readAsBytesSync();
    String name = DateTime.now().millisecondsSinceEpoch.toString();

    // 上传文件到Firebase Storage
    var pdfFile = FirebaseStorage.instance.ref().child(name).child("/.pdf");
    UploadTask task = pdfFile.putData(file);
    TaskSnapshot snapshot = await task;
    url = await snapshot.ref.getDownloadURL();
    String ref = name + "/.pdf"; // 设置文件引用路径

    // 将文件信息上传到Firestore
    await FirebaseFirestore.instance.collection("file").doc().set({
      'fileUrl': url,
      'num': "CV#" + number.toString(),
      'ref': name + "/.pdf" // 存储文件引用路径
    });
  }

  Future<void> deleteFile() async {
    if (_selectedRef != null) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('确定要删除该文件吗?'),
            actions: <Widget>[
              TextButton(
                child: const Text('取消'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
              TextButton(
                child: const Text('删除'),
                onPressed: () async {
                  await deleteFirebaseData();
                  Navigator.of(context).pop();
                  ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text("文件已删除")));
                },
              ),
            ],
          );
        },
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("请先选择要删除的文件")));
    }
  }

  Future<void> deleteFirebaseData() async {
    if (_selectedRef == null) {
      ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("请先选择要删除的文件")));
      return;
    }

    // 构建完整的文件引用路径
    String ref = _selectedRef!;
    if (!ref.startsWith("/")) {
      ref = "/" + ref;
    }
    ref = ref.substring(0, ref.lastIndexOf("/") + 1) + ".pdf";

    // 判断文件是否存在
    bool exists = true;
    try {
      await FirebaseStorage.instance.ref(ref).getMetadata();
    } on FirebaseException catch (e) {
      if (e.code == 'object-not-found') {
        exists = false;
      }
    }

    if (exists) {
      await FirebaseStorage.instance.ref(ref).delete();
      await FirebaseFirestore.instance
          .collection("file")
          .where("ref", isEqualTo: _selectedRef)
          .get()
          .then((snapshot) {
        snapshot.docs.first.reference.delete();
      });
      setState(() {
        _selectedRef = null;
      });
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("选中的文件不存在")));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const NavigationDrawerMenu(),
      appBar: AppBar(
        backgroundColor: Colors.green,
        title: const Text('PDF'),
      ),
      body: StreamBuilder(
          stream: FirebaseFirestore.instance.collection("file").snapshots(),
          builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                  itemCount: snapshot.data!.docs.length,
                  itemBuilder: (context, i) {
                    QueryDocumentSnapshot x = snapshot.data!.docs[i];
                    return InkWell(
                      onTap: () {
                        setState(() {
                          selectedSnapshot = x; // 保存选中的文件快照
                        });
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => View(
                                      url: x['fileUrl'],
                                    )));
                      },
                      child: Container(
                        margin: const EdgeInsets.symmetric(vertical: 10),
                        child: Text(x["num"]),
                      ),
                    );
                  });
            }
            return const Center(
              child: CircularProgressIndicator(),
            );
          }),
      floatingActionButton: Row(
        children: [
          FloatingActionButton(
            heroTag: "btn1",
            onPressed: () {
              setState(() {
                _selectedRef = selectedSnapshot['ref']; // 保存选中文件的引用
              });
              deleteFile();
            },
            child: const Icon(Icons.delete),
          ),
          const SizedBox(width: 10),
          Expanded(
            child: FloatingActionButton(
              heroTag: "btn2",
              onPressed: () => uploadDataToFirebase(),
              child: const Icon(Icons.add),
            ),
          ),
        ],
      ),
    );
  }
}

class View extends StatelessWidget {
  PdfViewerController? _pdfViewerController;
  final url;

  View({this.url});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("PDF 预览"),
      ),
      body: SfPdfViewer.network(
        url,
        controller: _pdfViewerController,
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者GermanBMxD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:59:54