当前位置: 首页 > 知识库问答 >
问题:

Flutter Web上传到Firestore

常源
2023-03-14

我在Flitter web和将图像上传到Firestore时遇到问题。我很确定问题在于图像采集器,因为普通(移动)图像采集者不适用于web。普通图像选取器返回一个文件,但备选图像选取器web返回一个图像,该图像在上传时被拒绝,因为它期望<code>未来

image_picker_web有一个替代方案来返回我使用过的Uint8List,然后通过dart: html转换为File-并上传罚款,但图像已损坏且无法查看。

以下是我所做的:

按下按钮时 - 选择图像作为 Uint8 列表

                  onPressed: () async {
                    //Upload Image as Uint8List
                    imageBytes = await ImagePickerWeb.getImage(asUint8List: true);
                    //Convert Uint8List to Image
                    _image = Image.memory(imageBytes);
                    //Show new image on screen
                    setBottomSheetState(() {
                      image = _image;
                    });
                  },

使用飞镖将Uint8列表转换为文件并以用户身份将文件和名称作为用户 UID.png (PNG 上传)

 imageFile = html.File(imageBytes, '${user.uid}.png');

使用方法上传文件

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

String url;

  Future<String> uploadProfilePhoto(html.File image, {String imageName}) async {

    try {
      //Upload Profile Photo
      fb.StorageReference _storage = fb.storage().ref('profilephotos/$imageName.png');
      fb.UploadTaskSnapshot uploadTaskSnapshot = await _storage.put(image).future;
      // Wait until the file is uploaded then store the download url
      var imageUri = await uploadTaskSnapshot.ref.getDownloadURL();
      url = imageUri.toString();

    } catch (e) {
      print(e);
    }
    return url;
  }

呼叫方法

location = await uploadProfilePhoto(imageFile, imageName: '${user.uid}');

向火库数据库添加包括位置在内的数据

//Pass new user ID through to users Collection to link UserData to this user
await AdminUserData(uid: user.uid).updateAdminUserData(name: userName, email: userEmail, profilephoto: location);

一切工作正常,只是图像似乎被破坏,它还以几乎两倍的文件大小返回,这显然意味着文件不是作为图像返回的..

共有3个答案

江德润
2023-03-14

这是一个旧帖子,但以防有人仍然需要帮助,因为我一直在寻找数小时来解决这个问题。这就是我的做法。

    < li >导入image_picker_web我使用的是2.0.3版本。 < li >在button ontap侦听器上使用ImagePickerWeb.getImageInfo获取图像信息。
var fileInfo = await ImagePickerWeb.getImageInfo;
Image.memory(fileInfo.data!,width: 180),
final firebasefileLocation = firebaseStorageLocation.child('${DateTime.now()}_${fireInfo.fileName}');
 await firebasefileLocation.putData(img.data!);

这就是我的文件在手机和网络上的工作方式。关于这一点以及如何在image_picker_web页面上选择多个图像的更多信息。您可以使用这里的概念,使其与IOS和Android跨平台。

import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker_web/image_picker_web.dart';

class ImagePickerDemo extends StatefulWidget {
  const ImagePickerDemo({Key? key}) : super(key: key);

  @override
  _ImagePickerDemoState createState() => _ImagePickerDemoState();
}

class _ImagePickerDemoState extends State<ImagePickerDemo> {
  MediaInfo? _imageInfo;

  Future<void> _pickImage() async {
    var fileInfo = await ImagePickerWeb.getImageInfo; //get image
    if (fileInfo.data == null) return; // user did not choose image.
    setState(() {
      _imageInfo = fileInfo; // save image
    });
  }

  Future<void> _uploadImage() async {
    if (_imageInfo == null) return;
    final firebaseStorageLocation =
        FirebaseStorage.instance.ref().child('product_images');
    final imageInfo = _imageInfo as MediaInfo;
    _imageInfo as MediaInfo;
    final firebasefileLocation = firebaseStorageLocation
        .child('${DateTime.now()}_${imageInfo.fileName!}');

    await firebasefileLocation.putData(imageInfo.data!);
    final urlToUseLater = await firebasefileLocation.getDownloadURL();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(onPressed: _pickImage, child: Text('Choose Image')),
        ElevatedButton(
            onPressed: _imageInfo == null ? null : _uploadImage,
            child: Text('Upload Image')),
        Image.memory(
          _imageInfo!.data!,
          width: 180,
        )
      ],
    );
  }
}
穆招
2023-03-14

这是一个可能的实现:

import 'dart:developer';

import 'package:file_picker/file_picker.dart';
import 'package:firebase_storage/firebase_storage.dart';

/// Opens a file picker and uploads a single selected file to Firebase storage.
/// Returns a download URL if upload is successful or null if the operation is 
/// aborted.
/// 
/// Throws an exception if more than one file is selected or the selected file 
/// size exceeds 300KB
Future<String?> pickAndUploadFile() async {
  final ref = FirebaseStorage.instance.refFromURL('gs://YOUR-PROJECT.appspot.com');
  String? res;
  final filePickerRes = await FilePicker.platform.pickFiles();
  if (filePickerRes != null) {
    if (filePickerRes.count == 1) {
      final file = filePickerRes.files.single;
      if (file.size > 300000) {
        throw Exception('File must be less than 300KB');
      }
      final upTask = ref.child('uploads/${file.name}').putData(file.bytes!);
      final snapshot = upTask.snapshot;
      res = (await snapshot.ref.getDownloadURL()).toString();
    } else {
      throw Exception('only one file allowed');
    }
  }
  log('downloadUrl: $res');
  return res;
}

结果 (快照) 是一个限定 URL,您可以将其与加载 URL 的任何图像小部件一起使用。

颛孙沈义
2023-03-14

我还没有尝试过你提到的替代方案,但下面的方法以前在Flutter网络和Firebase上对我有用。上传输入的事件监听器适用于大多数平台。关于document.body.append的最后一部分将确保它也适用于移动Safari。

  Future<void> _setImage() async {
    final completer = Completer<String>();
    InputElement uploadInput = FileUploadInputElement();
    uploadInput.multiple = false;
    uploadInput.accept = 'image/*';
    uploadInput.click();
    
    uploadInput.addEventListener('change', (e) async {
      // read file content as dataURL
      final files = uploadInput.files;
      Iterable<Future<String>> resultsFutures = files.map((file) {
        final reader = FileReader();
        reader.readAsDataUrl(file);
        reader.onError.listen((error) => completer.completeError(error));
        return reader.onLoad.first.then((_) => reader.result as String);
      });

      final results = await Future.wait(resultsFutures);
      completer.complete(results[0]);
    });

    
    document.body.append(uploadInput);
    final String image = await completer.future;

    widget.newImage = uploadInput.files[0];

    // Upload to Firebase
    uploadToFirebase(widget.newImage); // This is dart:html File

    uploadInput.remove();
  }

然后上传到Firebase存储:

uploadToFirebase(String imageName, File file) async {
 Firebase.UploadTask task = storage.refFromURL('gs://.../images/' + imageName).put(file); 
}
 类似资料:
  • 为了排除可能的其他问题,我可以使用update.json方法成功地将状态更新发布到Twitter。 我还尝试使用client.addfile方法和Fiddler,看起来一切都就绪了。但我不断得到的错误信息是

  • 在Bot编辑界面,选择Triggers栏,添加Post-Interation Script,将一下脚本复制进编辑框。配置好自己的User Key,和API Key。 #!/bin/sh IPA_NAME=$(basename "${XCS_ARCHIVE%.*}".ipa) IPA_PATH="${XCS_OUTPUT_DIR}/ExportedProduct/Apps/${IPA_NAME}"

  • 将文件夹或裸数据上传到swarm网络。 调用: web3.bzz.upload(mixed) 参数: mixed - String|Buffer|Uint8Array|Object: 要上传的数据,可以是文件内容、Buffer/Uint8Array、多个 文件,也可以是一个目录或文件名(仅在node.js中有效)。可以使用以下类型: String|Buffer|Uint8Array: 文件内容,

  • 问题内容: 我有一个问题,从选择a 获取将上述对象上传到具有此表结构的MySQL表 并且从该Java代码来看,该方法是该类的静态方法,其中它向所述MySQL数据库返回默认的DriverManager的新实例。另一件事,我使用的是包装而不是包装。 当我尝试运行该程序时,它返回错误,导致该行具有以下堆栈跟踪: 我该如何解决这个问题? 问题答案: 表示您的JDBC驱动程序未实现。 使用较旧的版本或更新驱

  • 我正在尝试创建一个上传到我的 Azure blob 的 Azure 函数。我试图避免从我的Web服务器(Linux vm)上传的原因是因为我注意到azure对数据传输(从客户端到链接到VM的虚拟网络的流量)收费。我也担心这会对Web服务器造成网络流量。这些真的是 Azure 函数可以解决的问题吗? 为了创建这个函数,我使用了Visual Studio,并在我的blob存储中添加了一个带有超文本传输

  • 我是vaadin的新手,我正在使用Spring和vaadin开发我的第一个应用程序。 现在我正试图在数据库中保存一个图像。我遵循了瓦丁书(upload component)中对upload component的描述 如果我想将其存储在数据库中,我需要更改什么?你能给我举个例子吗?