[英]Flutter Web Upload to Firestore
我在使用 Flutter web 并将图像上传到 Firestore 时遇到问题。 我很确定问题出在图像选择器中,因为普通(移动)图像选择器不适用于网络。 普通图像选择器返回一个文件,但替代image_picker_web返回一个图像,该图像在上传时被拒绝,因为它期待一个Future<File>
。
image_picker_web有一个替代方法可以返回我使用过的Uint8List
,然后通过dart:html
转换为File
- 并上传正常,但图像已损坏且无法查看。
这是我所做的:
On Button Press - Pick Image as Uint8List
> Convert to Image
, Store in memory and Display on Screen
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;
});
},
转换Uint8List
到File
使用dart:html
File
和名称为用户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}');
将包括位置在内的数据添加到 Firebase 数据库
//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);
一切正常,只是图像似乎已损坏,它也以几乎两倍的文件大小返回,这显然意味着文件不会作为图像返回..
我没有尝试过你提到的替代方案,但下面在 Flutter web 和 Firebase 上对我有用。 uploadInput 的事件侦听器适用于大多数平台。 关于 document.body.append 的最后一部分将确保它也适用于 Mobile 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);
}
这是一个可能的实现:
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;
}
结果 ( snapshot.ref.getDownloadURL()
) 是一个合格的 URL,您可以将其用于任何加载 URL 的图像小部件。
这是一篇旧帖子,但以防万一有人仍然需要帮助,因为我已经搜索了几个小时来解决这个问题。 这就是我的做法。
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,
)
],
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.