Flutter Web putData doesn't Put the Data - firebase

With Flutter Web, Firebase Storage, Getting an XFile from Image_Picker, I am trying to implement the putData method, (which actually executes without errors). A putFile implementation works fine for me for mobile. I need to use putData for Web.
This simplified code executes without errors, and file name, date, etc all populate in Storage, but without the actual file (9 bytes displayed as size).
I get an XFile from Image_Picker. The sample implementation from flutterfire's storage example also uses XFile and putData here.
Future<void> _startUpload(XFile file) async {
firebase_storage.FirebaseStorage _storage = firebase_storage.FirebaseStorage.instance;
firebase_storage.UploadTask? _uploadTask;
String filePath = 'filePath';
final metadata = firebase_storage.SettableMetadata(
contentType: 'image/jpeg',
);
Uint8List bytesFile = await file.readAsBytes();
final uploadTask = _storage.ref().child(filePath).putData(bytesFile, metadata);
final snapshot = await uploadTask;
final url = await snapshot.ref.getDownloadURL();
debugPrint('here is the download url: $url');
}

Just going to leave this here for future users who encounter this until the bug is fixed. The XFile method fromData isn't functioning properly as detailed here.
This was my issue. If you use cross_file or image_picker with a crop utility that required you to get an Xfile.fromData, it will fail until this is updated.

Related

How can i get Image URL from Firebase Storage to Firebase Database without uploading image from my app?

I upload one image from my computer to Firebase Storage and now I want that image to get in my Firebase database with his information and display it in my app. I can display information but cant display images. I google also but in every answer, they say first to upload the image to firebase storage from the app. then get his URL in the database and I don't want to upload from my app.
So if someone know then help.
You Can Get the download link for your image Like this
static final firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
String url = await storage
.ref('YourImagePath')
.getDownloadURL();
In addition to SARADAR21's excellent answer on how to get the data for a file at a known path, you can also list the files in Cloud Storage through the API, in case you don't know the path.
From that documentation:
final storageRef = FirebaseStorage.instance.ref();
final listResult = await storageRef.listAll();
for (var prefix in listResult.prefixes) {
// The prefixes under storageRef.
// You can call listAll() recursively on them.
}
for (var item in listResult.items) {
// The items under storageRef.
}
You can then use the references you get this way, and call getDownloadUrl() to get a download URL for each of them.
Future<QuerySnapshot?> getDataFromFirebase() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
FirebaseFirestore.instance
.collection('Images')
.get()
.then((QuerySnapshot? querySnapshot) {
querySnapshot!.docs.forEach((doc) {
List<dynamic> allImageData = doc["image_data"];
storeImageList = allImageData.map((i) => i.toString()).toList();
});
prefs.setStringList("imageList", storeImageList);
});
}

Flutter : How to upload image to firestore in form

Hay, I'm new in firestore and a little bit confused about uploading data to firestore. let's take an example, I have a form format like this :
so, there is a data (name, DoB) form and upload image form. as far I know is to store data collection (like name and Date of Brith section) is using the cloud_firestore plugin, otherwise to store the image file is using firebase_store plugin.
then, how do I use both plugins at the same time when uploading forms like this? or is there another method to upload image with a form?
Thanks.
You need to first upload the image to firebse_storage , get a link and create the firestore document.
example
// upload the file helper
Future<String?> uploadFile(FilePickerResult? fileName) async {
Uint8List? fileBytes = fileName!.files.first.bytes;
// Create a Reference to the file
var filename = DateTime.now().toLocal().toIso8601String();
if (kIsWeb) {
firebase_storage.Reference ref = firebase_storage.FirebaseStorage.instance
.refFromURL(storageRefFbS)
.child("files")
.child(filename + "." + fileName.files.first.extension!);
await ref.putData(fileName.files.first.bytes!);
var dwonloadurl = await ref.getDownloadURL();
log(dwonloadurl);
return dwonloadurl;
}
}
//upload a file/image
var downloadUrl =
await firebaseHelper.uploadFile(myPickedFile);
// save the data
FirebaseFirestore.instance
.collection("myData")
.set({
"sname": "name",
"url":downloadUrl,
});

How to store Firebase Storage Items to local cache to save bandwidth costs?

I'm enrolled in a project using Flutter and Firebase and I'm having trouble with bandwidth limits. The free quota is 1gb per day and I have a list with 100 images (and some files).
Is there a way to minimize the bandwidth costs through caching this files in local phone cache to not have to get the items from DB each time I open the screen?
Is there a package or something like this to do it?
I think you can do it easily with cached network image
If you want more control, I created a simple function to do this job, you can customize it further according to your needs:
import 'dart:typed_data';
import 'dart:io';
import 'package:http/http.dart' show get;
Future<File> getCachedImageFile(final String imageId) async {
final Directory temp = await getTemporaryDirectory();
final String fullPathName = '${temp.path}/images/$imageId';
final File imageFile = File(fullPathName);
if (imageId == null) return null;
if (await imageFile.exists() == false) { // will guarantee that you don't make the API request (or just get image from url if unprotected)
final String endpoint = 'http://www.mywebsiteorRESTapi.com/'
String imgUrl = endpoint + imageId + '.png';
var response = await get(imgUrl);
try {
await imageFile.create(recursive: true);
if (response.bodyBytes != null)
await imageFile.writeAsBytes(response.bodyBytes);
return imageFile;
} on Exception catch (exception) {
throw 'could not write image $exception';
}
}
return imageFile;
}
In your FutureBuilder:
future: getCachedImageFile('1VsSbB4Kh7Ab7spjQBA');
...
return Image.file(snapshot.data)
You can use CachedNetworkImage package to avoid downloading the image every time. It's simple to use and you just need to pass the URL to the Widget:
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
To control how long the image is cached*, make sure you add cache header to your images when you upload them so they get cached properly (in the browser too if you're using flutter web):
final contentType = 'image/*';
final cacheControl = 'public, max-age=31556926'; // seconds -- ie 31556926 == one year
final uploadTask = reference.putData(
image.data,
SettableMetadata(
cacheControl: cacheControl,
contentType: contentType,
));
So make sure to store the URL of the images when you upload them and just pass the URL to the users to get the images instead of downloading the images directly from FirebaseStorage in case you're doing that.
*I believe the package default is 7 days if no cache header is available but I cannot confirm.

Flutter Firestorage getDownloadUrl() returns NoSuchMethodError

inside my Flutter app I'm trying to upload an image to Firebase Storage and get the URL afterwards. The image is getting uploaded and I can see it in the web interface, but when I call getDownloadUrl() on a valid reference (I can see the relative path with debugger) I get type 'NoSuchMethodError' is not a subtype of type 'Exception' and the actual error is happening inside method_channel_reference.dart where for some reason, where storage is null and as such storage.app throws the Error.
#override
Future<String /*!*/ > getDownloadURL() async {
try {
Map<String, dynamic> data = await MethodChannelFirebaseStorage.channel
.invokeMapMethod<String, dynamic>(
'Reference#getDownloadURL', <String, dynamic>{
'appName': storage.app.name,
'maxOperationRetryTime': storage.maxOperationRetryTime,
'maxUploadRetryTime': storage.maxUploadRetryTime,
'maxDownloadRetryTime': storage.maxDownloadRetryTime,
'bucket': storage.bucket,
'path': fullPath,
});
return data['downloadURL'];
} catch (e) {
throw convertPlatformException(e);
}
}
The upload code is this:
final uploadTask = _firebaseStorage.ref().child(storagePath).putFile(recipeImage);
try {
await uploadTask.whenComplete(() {});
final url = await uploadTask.snapshot.ref.getDownloadURL();
return right<RecipeFailure, String>(url);
} catch (e) {
return left<RecipeFailure, String>(RecipeFailure.imageUploadFailed());
}
I'm using
firebase_core: ^0.7.0
firebase_auth: ^0.20.0+1
firebase_storage: ^7.0.0
cloud_firestore: ^0.16.0
I tried cleaning, rebuilding and downgrading dependencies. At this point I don't how where else to look. I guess the issue is with the storage instance being removed or not initialized at all, but why does the upload work then? Any help is welcomed.
I hope this can help you, but you can store the link in each upload in the document for each product or user wherever it is.
In this method, for example, you can retrieve the link file from the same document, and you do not need another way to retrieve it.
In this code you can upload the file and restore the downloadUrl when you have finished uploading the file.
static Future<dynamic> uploadFile(
{#required File imageFile, #required String folderPath}) async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
Reference reference =
FirebaseStorage.instance.ref().child(folderPath).child(fileName);
TaskSnapshot storageTaskSnapshot = await reference.putFile(imageFile);
// TaskSnapshot storageTaskSnapshot = uploadTask.snapshot;
print(storageTaskSnapshot.ref.getDownloadURL());
var dounloadUrl = await storageTaskSnapshot.ref.getDownloadURL();
return dounloadUrl;
}
When I changed from
#lazySingleton
FirebaseStorage get firebaseStorage => FirebaseStorage.instanceFor(bucket: "bucket-url");
to this
#lazySingleton
FirebaseStorage get firebaseStorage => FirebaseStorage.instance;
the error disappeared and everything was working properly.
The main reason I have the bucket URLs there was because I was working with project flavors and two Firebase projects. The seperate google-services.json seem to be enough for Android (haven't tested iOS until now). However, why the upload was working, but download not is still a big mistery to me.

I cannot put images in firestorage since it asks for a file

I've been working on an app with some apis in flutter, one of the is flutter_signature_pad, since this api saves a signature as an image I cannot seem to save it in firestorage since it only accepts file types.
Any help would be greatly appreciated
Here's a snippet of the relevant code:
onPressed: () async {
final sign = _sign.currentState;
//retrieve image data, do whatever you want with it
final image = await sign.getData();
StorageUploadTask uploadTask =
storageReference.putFile(image);
await uploadTask.onComplete;
print('File Uploaded');
sign.clear();
}
final image =
await sign.getData();
await image.writeAsBytes(byteData.buffer.asUint8List(
byteData.offsetInBytes, byteData.lengthInBytes));
or You can do is save image to a directory and then after using it delete it then there you can use this
final file =
File('${systemTempDir.path}/$imageName.jpeg');
await file.writeAsBytes(byteData.buffer.asUint8List(
byteData.offsetInBytes, byteData.lengthInBytes));
I used This Reference and If you see in the example of the library Flutter Signature pad they also write or encode data in a similar format

Resources