繁体   English   中英

Flutter web - 上传图片文件到Firebase存储

[英]Flutter web - Upload Image File to Firebase Storage

在flutter web上,我从电脑上取了一个图片文件,得到一个File图片object,然后我要上传到Firebase Storage。 对于应用程序的 Android 和 iOS 版本,我使用了 Firebase Cloud Function 和 http 多部分请求。 它有效,但对于 web 版本的应用程序,它没有。 所以,

如何将 html 图像文件直接或通过云 Function 上传到 Firebase 存储?

最后我设法找到了解决这个问题的方法。 为了实现这一点,我需要安装两个依赖项, firebaseUniversal_html 虽然很难找到解决方案,但它的实现其实很简单。 这是我用来将 html 图像文件上传到 Firebase Storage 到“images”文件夹的函数代码:

import 'dart:async';
import 'package:universal_html/prefer_universal/html.dart' as html;
import 'package:firebase/firebase.dart' as fb;

Future<Uri> uploadImageFile(html.File image,
      {String imageName}) async {
    fb.StorageReference storageRef = fb.storage().ref('images/$imageName');
    fb.UploadTaskSnapshot uploadTaskSnapshot = await storageRef.put(image).future;
    
    Uri imageUri = await uploadTaskSnapshot.ref.getDownloadURL();
    return imageUri;
}

我希望它可以帮助和我有同样需求的人。

以下是适用于我上传图片的完整html.Filehtml.File对我不起作用,文件已上传但您会在 firebase 存储中看到Error loading preview ,因此只需直接传递字节对我html.File

要显示图像,您可以将mediaInfo.bytes与支持字节的小部件mediaInfo.bytes使用,例如FadeInImage您可以使用MemoryImage(mediaInfo.bytes)Image.memory(mediaInfo.bytes)

使用的包:

  1. 火力基地
  2. image_picker_web
  3. 小路
  4. mime_type
    Future<MediaInfo> imagePicker() async {    
        MediaInfo mediaInfo = await ImagePickerWeb.getImageInfo;
        return mediaInfo;
     }
     
     Future<Uri> uploadFile(
          MediaInfo mediaInfo, String ref, String fileName) async {
        try {
          String mimeType = mime(Path.basename(mediaInfo.fileName));

          // html.File mediaFile =
          //     new html.File(mediaInfo.data, mediaInfo.fileName, {'type': mimeType}); 
          final String extension = extensionFromMime(mimeType);

          var metadata = fb.UploadMetadata(
            contentType: mimeType,
          );

          fb.StorageReference storageReference =
              fb.storage().ref(ref).child(fileName + ".$extension");

          fb.UploadTaskSnapshot uploadTaskSnapshot =
              await storageReference.put(mediaInfo.data, metadata).future;

          Uri imageUri = await uploadTaskSnapshot.ref.getDownloadURL();
          print("download url $imageUri");
          return imageUri;
        } catch (e) {
          print("File Upload Error $e");
          return null;
        }
      }

2022年的答案

TLDR:在上传之前使用cross_file package 将文件转换为 XFiles。

Select 图片

使用image_picker package 到 select 一张图片。 这适用于 Android、iOS 和 web。

Future<String?> selectPicture(ImageSource source) async {
  XFile? image = await imagePicker.pickImage(
    source: source,
    maxHeight: 1000,
    maxWidth: 1000,
  );

  return image?.path;
}

将 XFile 转换为 Uint8List

String path = selectPicture(ImageSource.gallery);
Uint8List imageData = await XFile(path).readAsBytes()

将 Uint8List 上传到云存储

UploadTask uploadTask = storageReference.putData(imageData);

要在 Flutter for Web 应用程序中访问 Cloud Storage,您可以使用firebase-dart插件 您可以在 repo 中找到通过firebase-dart访问存储的示例。

在结合了这么多帖子后,我做到了,并且有效!

不,您只是不需要任何类型的 Universal_HTML 或其他 image_picker_web。 只需坚持使用图像选择器( https://pub.dev/packages/image_picker )。 并使用下面的代码,就像我用来将图像上传到 Firebase 存储一样,它可以在 IOS、Android、Web 的所有方式中工作,我希望您已经添加了 ios 和 android 的权限。 让我们开始!

Import

import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as Path;

Call this method when you want to open a file picker in any of the above platforms!

chooseImage() async {
PickedFile? pickedFile = await ImagePicker().getImage(
      source: ImageSource.gallery,
    );
}

now you've file in pickedFile use kIsWeb to find out if it's web or not!

uploadImageToStorage(PickedFile? pickedFile) async {
if(kIsWeb){
Reference _reference = _firebaseStorage
        .ref()
        .child('images/${Path.basename(pickedFile!.path)}');
    await _reference
        .putData(
      await pickedFile!.readAsBytes(),
      SettableMetadata(contentType: 'image/jpeg'),
    )
        .whenComplete(() async {
      await _reference.getDownloadURL().then((value) {
        uploadedPhotoUrl = value;
      });
    });
 }else{
//write a code for android or ios
}

}

添加到@WebRooseDevelopment,您可能还需要更新 index.html 文件以包含新的 firebase 版本。

' src="https://www.gstatic.com/firebasejs/8.6.1/firebase-storage.js">'

 void uploadImage({required Function(File? file) onSelected}) {
    var uploadInput = FileUploadInputElement()..accept = 'image/*';
    uploadInput.click();

    uploadInput.onChange.listen((event) async {
      final file = uploadInput.files!.first;

      final reader = FileReader();
      reader.readAsDataUrl(file);
      reader.onLoadEnd.listen((event) async {
        onSelected(file);
      });
    });
  }

  void uploadToStorage() {
    final dateTime = DateTime.now();
    final userId = FirebaseAuth.instance.currentUser!.uid;
    imagePath = '$userId/$dateTime'.replaceAll(' ', '');

    uploadImage(onSelected: (file) {
      try {
        fb.storage().refFromURL('{reference url from firebase}').child(imagePath).put(file);
      } catch (e) {
        print('uploadImage $e');
      }
    });
  }

单击按钮时调用 uploadToStorage 函数并显示图像,

 Future<Uri> downloadImageUrl(String? path) {
    print(
        'downloadImageUrl:: ${fb.storage().refFromURL('{reference url from firebase}').child(path!).getDownloadURL()}');
    return fb
        .storage()
        .refFromURL('gs://onehourappbuildpractice.appspot.com/')
        .child(path)
        .getDownloadURL();
  }

FutureBuilder<Uri>(
                      future: downloadImageUrl(
                          controller.hiddenGemList[i].imagePath!),
                      builder: (context, snapshot) {
                        if (snapshot.connectionState ==
                            ConnectionState.waiting) {
                          return Center(
                            child: CircularProgressIndicator(),
                          );
                        }
                        return Container(
                            height: 100,
                            width: 200,
                            child: FadeInImage.assetNetwork(
                              image: snapshot.data.toString(),
                              placeholder: 'assets/placeholder_image.jpeg',
                            ));
                      })

Select 图片

使用 image_picker package 到 select 一张图片。

Future<void> imgFromGallery() async {

    final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    
    Uint8List imageData = await XFile(pickedFile!.path).readAsBytes();

    uploadImage(imageData );
}

上传到云存储

使用 UUID package 创建唯一名称。

 Future<String> uploadImage(Uint8List xfile) async {

    Reference ref = _storage.ref().child('Folder');
    String id = const Uuid().v1();
    ref = ref.child(id);

    UploadTask uploadTask = ref.putData(
      xfile,
      SettableMetadata(contentType: 'image/png'),
    );
    TaskSnapshot snapshot = await uploadTask;
    String downloadUrl = await snapshot.ref.getDownloadURL();
    return downloadUrl;
  }

上传到 Cloud Firestore

  Future<void> addData() async {
    try {
      await FirebaseFirestore.instance.('DBname').add({'image':downloadUrl});
      
    } on FirebaseException catch (e) {
     
    } catch (_) {
      
    }
  }

在 flutter Web 应用程序中显示图像

  1. 打开谷歌云控制台select 你的项目并通过单击顶部导航栏中的>_图标按钮启动云终端 session。
  2. 单击打开编辑器按钮,然后创建cors.json文件并输入下面的代码并保存。
[
  {
    "origin": ["*"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
  1. 打开终端 (Cloud Shell) 并运行以下代码。
 gsutil cors set cors.json gs://your-bucket

注意:从 firebase 存储中替换您的存储桶 ID

  1. 现在在Flutter Web App中制作Ui
Image.network(widget.project.image!)

注意:仅当您已经设置了以下代码

网站/index.html

<HTML>
....
<body>
<script type="module">

    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-app.js";
    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-storage.js";
    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-firestore.js";
 
const firebaseConfig = {
    apiKey: "....",
    authDomain: "...",
    projected: "....",
    storageBucket: "...",
    messagingSenderId: "....",
    appId: "....",
    measurementId: "...."
  };
  
    const app = initializeApp(firebaseConfig);
  </script>
....
</body>
</html>

相关附录:如何下载:为什么这是一个如此隐藏的秘密,我不知道。 感谢Learn Flutter Code 提供了这个不错的小教程。

不要让 Firebase Storage 成为依赖项,只需将 Firebase 设置为:

import 'package:firebase/firebase.dart' as fb;

然后创建一个方法:

        Future<Uri> myDownloadURL() async {return await fb.storage().refFromURL('gs://<your storage reference>').child('$id.jpg').getDownloadURL();}

像这样从 FutureBuilder 调用它:

        FutureBuilder<Uri>(
        future: myDownloadURL(),
        builder: (context, AsyncSnapshot<dynamic> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return <Something as a placeholder>;
          }
          return CircleAvatar(
            radius: backgroundRadius * 2,
            child: Image.network(snapshot.data.toString()),
          );
        },
      )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM