Firebase downloadUrl and Access token conflict - firebase

I am working on a simple app using Flutter to retrieve an image I manually uploaded to my firebase storage and display it on the screen. The upload is always successful, but I cannot get the image because the "dowloadURL" is showing "access token" instead.
Am i missing something somewhere? Someone please help me?
enter image description here

For uploading the file and directly get the image downloadUrl after, I've made some static functions which I call on my page like this:
StorageUploadTask imageUploadTask = await ImageProcessProvider.setImageToStorage(_destinationImage, generatedRandomId);
String imageDownloadUrl = await ImageProcessProvider.getImageDownloadUrlAfterUploading(imageUploadTask);
Static functions (including how I upload: 'setImageToStorage'):
import 'dart:async';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_picker_modern/image_picker_modern.dart';
class ImageProcessProvider {
static Future<String> getImageDownloadUrl(String imageId) async {
try {
final String downloadUrl = await FirebaseStorage.instance.ref().child(imageId + '.jpg').getDownloadURL();
return downloadUrl;
} catch (error) {
print('getImageDownloadUrl: $error');
throw error;
}
}
static Future<String> getImageDownloadUrlAfterUploading(StorageUploadTask uploadTask) async {
try {
final StorageTaskSnapshot url = (await uploadTask.onComplete);
final String downloadUrl = (await url.ref.getDownloadURL());
return downloadUrl;
} catch (error) {
print('getImageDownloadUrlAfterUploading: $error');
throw error;
}
}
static Future<StorageUploadTask> setImageToStorage(File image, String imageId) async {
try {
final String fileName = imageId + '.jpg';
final StorageReference storageRef = FirebaseStorage.instance.ref().child(fileName);
final StorageUploadTask uploadTask = storageRef.putFile(
File(image.path),
StorageMetadata(
contentType: 'image/jpeg',
),
);
return uploadTask;
} catch (error) {
print('setImageToStorage: $error');
throw error;
}
}
}
Hope this will help you.

Related

How to add multiple images in flutter (firebase)

how I can add multiple images and store them in an array in firebase ?
every container has a + button so the user can add single image per container then I WANT TO STORE them in my firebase
any help would be greatly appreciated ^^
what you are showing in your image is fbCloudStore which is use to store information in json structure.
To store the images you may use fbStorge.
here's an snippet I use on my project:
Future<String?> uploadFile({
required FilePickerResult file,
required String fileName,
required FirebaseReferenceType referenceType,
}) async {
try {
final ref = _getReference(referenceType);
final extension = path.extension(file.files.first.name);
final _ref = ref.child(fileName + extension);
late UploadTask uploadTask;
if (kIsWeb) {
uploadTask = _ref.putData(file.files.first.bytes!);
} else {
uploadTask = _ref.putFile(File(file.files.single.path!));
}
var url;
await uploadTask.whenComplete(
() async => url = await uploadTask.snapshot.ref.getDownloadURL());
print(url);
return url;
} on FirebaseException catch (_) {
print(_);
}
}
Note that I'm returning the URL of fbStorage in order to associate it with fbCloudStorage
final url =
await FirebaseStorageSer.to.uploadFile(
file: result,
fileName: STORAGE_USER_PROFILE_PICTURE,
referenceType: FirebaseReferenceType.user,
);
if (url != null) {
await FirebaseAuthSer.to
.updateUserProfile(photoUrl: url);
}
FirebaseReferenceType.user is just a simple enum to simplify ref targets.

Firebase _upload writes random downloadURL

Below is a simple firebase image uploader. The problem is that it sometimes uses another image's downloadURL as the value when it writes to Firestore. It uploads my image to cloud storage without a problem but then when it goes to write the location to firestore, it often uses the URL of another image. The full code is below but I have omitted the UI. How do I ensure that it writes the correct URL to firestore?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:path/path.dart' as path;
import 'package:image_picker/image_picker.dart';
class ImagePicky2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// Remove the debug banner
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.green),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
FirebaseStorage storage = FirebaseStorage.instance;
double? lat, lng;
File? file;
String? name, detail, pathImage, dateString;
// Select an image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
Future<XFile?> _upload(String inputSource) async {
FirebaseAuth auth = FirebaseAuth.instance;
User firebaseUser = auth.currentUser!;
final picker = ImagePicker();
try {
final pickedImage = await picker.pickImage(
source: inputSource == 'camera'
? ImageSource.camera
: ImageSource.gallery,
imageQuality: 25,
maxWidth: 1920);
final String fileName = path.basename(pickedImage!.path);
File imageFile = File(pickedImage.path);
try {
// Uploading the selected image with some custom meta data
await storage.ref(fileName).putFile(
imageFile,
SettableMetadata(customMetadata: {
'uploaded_by': firebaseUser.displayName!,
'description': 'Some description...'
}));
// Refresh the UI
setState(() {});
} on FirebaseException catch (error) {
print(error);
}
} catch (err) {
print(err);
}
photoUploadFirestoreDetails();
}
// Retriew the uploaded images
// This function is called when the app launches for the first time or when an image is uploaded or deleted
Future<List<Map<String, dynamic>>> _loadImages() async {
FirebaseAuth auth = FirebaseAuth.instance;
User firebaseUser = auth.currentUser!;
List<Map<String, dynamic>> files = [];
final ListResult result = await storage.ref().list();
final List<Reference> allFiles = result.items;
await Future.forEach<Reference>(allFiles, (file) async {
final String fileUrl = await file.getDownloadURL();
pathImage = await file.getDownloadURL();
final FullMetadata fileMeta = await file.getMetadata();
files.add({
"url": fileUrl,
"path": file.fullPath,
"uploaded_by": fileMeta.customMetadata?['uploaded_by'] ?? firebaseUser.displayName,
"description":
fileMeta.customMetadata?['description'] ?? 'No description'
});
});
return files;
}
Future<Null> photoUploadFirestoreDetails() async {
Firebase.initializeApp();
Map<String, dynamic> map = Map();
map['PathImage'] = pathImage;
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collectionReference =
firestore.collection('MarkerCollect');
await collectionReference.doc().set(map).then((
value) {
});
}
}```
The code is uploading random download urls to Firestore because you're getting the image path from the _loadImages method which loads up the files on storage instead of using the download url of the just uploaded file.
This is the problematic code:
Future<Null> photoUploadFirestoreDetails() async {
...
map['PathImage'] = pathImage;
...
}
Solution:
You can fix this by retrieving the download url just after the upload and passing it to the photoUploadFirestoreDetails method to be used in the Firestore upload.
You should also put the photoUploadFirestoreDetails in the try-catch.
Checkout the updated code below:
// _upload method
Future<XFile?> _upload(String inputSource) async {
FirebaseAuth auth = FirebaseAuth.instance;
User firebaseUser = auth.currentUser!;
final picker = ImagePicker();
try {
final pickedImage = await picker.pickImage(
source: inputSource == 'camera'
? ImageSource.camera
: ImageSource.gallery,
imageQuality: 25,
maxWidth: 1920);
final String fileName = path.basename(pickedImage!.path);
File imageFile = File(pickedImage.path);
try {
// Uploading the selected image with some custom meta data
final Reference storageReference = storage.ref(fileName);
await storageReference.putFile(
imageFile,
SettableMetadata(customMetadata: {
'uploaded_by': firebaseUser.displayName!,
'description': 'Some description...'
}));
final String downloadUrl = await storageReference.getDownloadURL();
// Refresh the UI
setState(() {});
await photoUploadFirestoreDetails(downloadUrl: downloadUrl);
} on FirebaseException catch (error) {
print(error);
}
} catch (err) {
print(err);
}
}
// photoUploadFirestoreDetails method
Future<Null> photoUploadFirestoreDetails({#required String downloadUrl}) async {
Firebase.initializeApp();
Map<String, dynamic> map = Map();
map['PathImage'] = downloadUrl;
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collectionReference =
firestore.collection('MarkerCollect');
var value = await collectionReference.doc().set(map);
}
Try this function to upload image to fire-storage and get Url
Future<String?> uploadAndGetUrl(File file) async {
try {
final Reference ref = FirebaseStorage.instance
.ref()
.child('profilePhoto')
.child(DateTime.now().microsecondsSinceEpoch.toString());
UploadTask uploadTask = ref.putFile(file);
await uploadTask.whenComplete(() {});
String url = await ref.getDownloadURL();
return url;
} catch (e) {
print('Firebase Storage Error is : $e');
return null;
}
}
OR you can just upload an image and get the image URL later.
Your upload image function looks okay. the name should be unique. otherwise, it returns a different image url.
Future<String> getUrl(String imageName) async {
try {
Reference storageRef = FirebaseStorage.instance.ref().child('profilePhoto/$logo');
String url = await storageRef.getDownloadURL();
return url;
} catch (e) {
return null;
}
}

Flutter Firebase Storage 0.5.0 upload file and video error

What I want to do: Upload a file and a video with Firebase Storage 0.5.0 and return url.
What current problem is: I can upload file and image with Firebase storage 0.5.0, but I can't return url. I also see my file and video uploaded in Firebase storage in Firebase console.
My code:
Future<String> _uploadFile(Reference ref, File file,
[SettableMetadata metadata]) async {
UploadTask uploadTask = ref.putFile(file, metadata);
uploadTask.whenComplete(() async {
try {} catch (onError) {
print("Error");
}
});
final url = await ref.getDownloadURL();
return url;
}
Future<String> uploadVideo(File video,
{String refName, SettableMetadata metadata}) async {
metadata = SettableMetadata(contentType: 'video/mp4');
final name = refName != null ? refName : path.basename(video.path);
final ref = _VideoRef.child(name);
return _uploadFile(ref, video, metadata);
}
Future<File> downloadImage(String imageUrl, String savePath) async {
final ref = _storage.ref(imageUrl);
var file = File(savePath);
await ref.writeToFile(file);
return file;
}
What the console told me:
FirebaseException (Firebase_storage/object-not-found). No object exist in desired reference.
How do I fix this?
Try the following:
uploadTask.whenComplete(() async {
try {
url = await ref.getDownloadURL();
} catch (onError) {
print("Error");
}
});
When the future completes, call getDownloadURL() to get the url.

How to upload pdf to firebase storage with flutter?

I'm using latest firebase_storage version now some methods and references of storage are updated ploadTask.onComplete does not support.
so how do I get uploaded pdf url?
Piece of code:
Future<String> uploadPdfToStorage(File pdfFile) async {
try {
Reference ref = FirebaseStorage.instance.ref().child('pdfs/${DateTime.now().millisecondsSinceEpoch}');
UploadTask uploadTask = ref.putFile(pdfFile, SettableMetadata(contentType: 'pdf'));
String downloadUrl = await (await uploadTask.onComplete).ref.getDownloadURL();
final String url = await downloadUrl;
print("url:$url");
return url;
} catch (e) {
return null;
}
}
Here's an edited code that should work with the latest firebase storage_package:
Future<String> uploadPdfToStorage(File pdfFile) async {
try {
Reference ref =
FirebaseStorage.instance.ref().child('pdfs/${DateTime.now().millisecondsSinceEpoch}');
UploadTask uploadTask = ref.putFile(pdfFile, SettableMetadata(contentType: 'pdf'));
TaskSnapshot snapshot = await uploadTask;
String url = await snapshot.ref.getDownloadURL();
print("url:$url");
return url;
} catch (e) {
return null;
}
}

Upload multi images to firestore using flutter and get it's download URLs and save all of URLs to firebase

I have a form that have images to upload , when the user try to press on "Submit" button i'm trying to upload list of images to firestore and get all of its URLs and then submit a form to "x" collection in firebase but the writing on "x" collocation done before upload the images and get it's URLs.
I thinks the problem with (async,await).
Appreciate to help me.
List<File> imagePaths= new List() ;
List<String> imageURL= new List() ;
Future<FirebaseUser> getUser() async {
return await _auth.currentUser();
}
Future<void> uploadPic(File _image) async {
String fileName = basename(_image.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(Random().nextInt(10000).toString()+fileName);
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_image);
var downloadURL = await(await uploadTask.onComplete).ref.getDownloadURL();
var url =downloadURL.toString();
imageURL.add(url); // imageURL is a global list that suppose to contain images URLs
print("\n ---------------------------\n downloadURL :"+ url);
print("\n ---------------------------\n imageURL :"+ imageURL.toString());
}
Submit(BuildContext context) {
//imagePaths is list of file
imagePaths.add(Front_image);
imagePaths.add(Back_image);
imagePaths.forEach((x) => {
uploadPic(x)
});
getUser().then((user) {
crudObj.addNew({
'uid': user.uid,
'name': name,
'images':imageURL,
}).then((result) {
Navigator.pop(context);
}).catchError((e) {
print(e);
});
});
}
You should call your Submit only once your upload task is complete. I would recommend implementing something like this:
Stream uploadImageToFirebaseStorage(File image, String fullPath) {
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(fullPath);
StorageUploadTask task = firebaseStorageRef.putFile(image);
return task.events;
}
And then listen to this Stream and only then submit:
uploadImageToFirebaseStorage(
image, 'path/imagename.jpg'
).listen((data) async {
StorageTaskEvent event = data;
if (data.type == StorageTaskEventType.success) {
String downloadUrl = await event.snapshot.ref.getDownloadURL();
await Submit(title, imageUrl: downloadUrl);
return true;
}
if (data.type == StorageTaskEventType.failure) return false;
});
Please take note that I did not re-write your code, I am sharing a possible implementation.

Resources