How to upload Assets to FirebaseStorage in Flutter? - firebase

Here is my challenge:
I'm using the following method to select multiple images from my phone gallery (package multi_image_picker:needs to be added in pubspec.yaml)
Future<void> loadAssets() async {
List<Asset> resultList = <Asset>[];
String error = 'No Error Detected';
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
for (int i = 0; i < resultList.length; i++) {
print('resultList[i].name: ${resultList[i].name}');
}
} on Exception catch (e) {
error = e.toString();
}
if (!mounted) return;
setState(() {
images = resultList;
_error = error;
});
}
My variable resultListstores instances of Assets. I would like to upload those assets to a certain path in my FirebaseStorage.
In the past, I was using the package image_picker: which allowed me to select only one image from my phone gallery. But the image_picker could store the selected images as Type of File instead of Assets and from the Type of File I'm able to get the image-path which I could use to upload the image to my FirebaseStorage.
But I have no clue how to upload the Assets getting from the method loadhAssets() to my FirebaseStorage.
Anyone has an idea how to solve that?
I hope my concern was clear enough.
Many thanks in advance :)

The image_picker package also allows you to pick multiple images, not just one. I have a sample implementation code here:
List<XFile> selectedImages = [];
Future<void> pickImages() async {
final pickedFileList = await ImagePicker().pickMultiImage();
if (pickedFileList != null) {
setState(() {
selectedImages = pickedFileList;
});
}
}
And here's how you can upload your selected images to Firebase Storage:
FirebaseStorage storage = FirebaseStorage.instance;
Reference storageRef = storage.ref();
List<String> imgURL = []; //to store url of uploaded images
Future<void> uploadSelectedImages() async {
for (var i = 0; i < selectedImages.length; i++) {
final ref = storageRef.child('Photos/image$i');
await ref.putFile(File(selectedImages[i].path)).whenComplete(() async {
await ref.getDownloadURL().then((value) { //upload and get URL
setState(() {
imgURL.add(value);
});
});
});
}
}
Hope this help!

Related

Flutter-Firestore:- Unable to upload image to firestore. its says reference object is not found

I am very new to Dart, and coding in general. I have produced this code after watching tutorials on YouTube. For the most part, I have been able to troubleshoot most of my problems on my own, here I feel I need some help. I have written code to upload photographs, but it is giving the following error. Please help me understand this.
I/flutter ( 7512): [firebase_storage/object-not-found] No object exists at the desired reference.
My code is here:-
Future uploadImagetoFB() async {
if (_image != null) {
try{
String fileName = Path.basename(_image.path);
print('The uploaded file name is: ${fileName}');
final Reference storageReference =
FirebaseStorage.instance.ref().child('profileImages');
_imageUrl = await storageReference.getDownloadURL();
print('The Image Url: $_imageUrl');
} catch (e){
print(e);
}
}
}
Future PickedImage(ImageSource source) async {
try {
final image = await ImagePicker()
.pickImage(source: source, maxWidth: 160, maxHeight: 160);
if (image == null) return;
setState(() {
_image = File(image.path);
});
uploadImagetoFB();
} on PlatformException catch (e) {
print('failed to Upload ');
}
}
To upload photos to Firebase, use the code below.
This is the string where I set the image URL :
String? url;
Code for image upload:
uploadImage() async {
final _firebaseStorage = FirebaseStorage.instance;
final _imagePicker = ImagePicker();
PickedFile image;
//Check Permissions
await Permission.photos.request();
var permissionStatus = await Permission.photos.status;
if (permissionStatus.isGranted) {
//Select Image
image = (await _imagePicker.getImage(source: ImageSource.gallery))!;
var file = File(image.path);
int uploadTimestamp = DateTime.now().millisecondsSinceEpoch;
if (image != (null)) {
Reference ref =
_firebaseStorage.ref().child('profileImages/$uploadTimestamp');
UploadTask uploadTask = ref.putFile(file);
var imageUrl = await (await uploadTask).ref.getDownloadURL();
setState(() {
url = imageUrl.toString();
});
} else {
print('No Image Path Received');
}
} else {
print('Permission not granted. Try Again with permission access');
}
}
Result of Firebase :
Profile Images folder :
Uploaded image :

Correct order to upload images on firebase

To upload images for an object created by a user I store the images (selected by the user) in an array 'imagesList' as a File. When the user clicked upload (whole object) the following method saves the data on firebase:
TextButton(
onPressed: () async {
await uploadImage();
await jobService.createJob(Job(
titleTextEditorController.text.trim(),
category,
false,
false,
finalImageList));
},
child: Text('upload')),
The List finalImageList is filled in the first method 'uploadImage()'. I sourced it out in another method to get the await statement. The Code:
uploadImage() async {
for (int i = 0; i < imageList.length; i++) {
_imageFile = imageList[i];
String fileName = Path.basename(_imageFile!.path);
Reference reference =
FirebaseStorage.instance.ref().child('uploads/$fileName');
firebase_storage.SettableMetadata(
contentType: 'image/jpeg',
customMetadata: {'picked-file-path': fileName});
UploadTask uploadTask = reference.putFile(_imageFile!);
uploadTask.whenComplete(() async {
try {
imageUrl = await reference.getDownloadURL();
print('imageUrl' + imageUrl);
finalImageList.add(imageUrl);
} catch (onError) {
print("Upload Error");
}
});
await Future.value(uploadTask)
.then((value) => {print('Upload file path ${value.ref.fullPath}')})
.onError((error, stackTrace) =>
{print('Upload file path error ${error.toString()}')});
}
}
But the method is not fast enough to store the imageUrl's in finalImageList, so the Images is online but its not connected to the object in firebase. Is there a possibility to upload it immediately or the save the imageUrl correctly? Or is my code just in the wrong order?
The FlutterFire UploadTask class extends Future, which means that you can use await on it to wait until the upload is done.
That means you can write your code much simpler as:
await reference.putFile(_imageFile!);
imageUrl = await reference.getDownloadURL();
finalImageList.add(imageUrl);
print('Upload file path ${value.ref.fullPath}')
With this change, your uploadImage will only complete after the download URL was added to finalImageList.

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.

How to add Flutter Firebase VIdeo Upload Progrese Indecator | Upload Progress Indicator |

How to add Flutter Firebase VIdeo Upload Progrese Indecator | Upload Progress Indicator |
Anyone can help me
MediaInfo compressVideo = await VideoCompress.compressVideo(
videoPath,
quality: VideoQuality.Res640x480Quality,
includeAudio: true,
);
print('video Compressing Done');
var uploadVideo = await FirebaseStorage.instance
.ref()
.child("videos/${Me.get().uid}/${videoDoc.id}")
.putFile(File(compressVideo?.path));
print('video Uploading Done');
final videoUrl = await uploadVideo.ref.getDownloadURL();
showToast("Upload Successful");
This should be a good example from it:
Future<void> handleTaskExample2(String filePath) async {
File largeFile = File(filePath);
firebase_storage.UploadTask task = firebase_storage.FirebaseStorage.instance
.ref("videos/${Me.get().uid}/${videoDoc.id}")
.putFile(File(compressVideo?.path));
task.snapshotEvents.listen((firebase_storage.TaskSnapshot snapshot) {
print('Task state: ${snapshot.state}');
print(
'Progress: ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100} %');
}, onError: (e) {
// The final snapshot is also available on the task via `.snapshot`,
// this can include 2 additional states, `TaskState.error` & `TaskState.canceled`
print(task.snapshot);
if (e.code == 'permission-denied') {
print('User does not have permission to upload to this reference.');
}
});
// We can still optionally use the Future alongside the stream.
try {
await task;
print('Upload complete.');
} on firebase_core.FirebaseException catch (e) {
if (e.code == 'permission-denied') {
print('User does not have permission to upload to this reference.');
}
// ...
}
}
I would also recommend to check the docs for more details.
finally, I'm getting the right answer.
This answer is perfectly works in my case.
//This is the document reference
Reference videoRef = FirebaseStorage.instance
.ref()
.child("videos/${Me.get().uid}/${videoDoc.id}");
//Here video is uploading and return UploadTask
UploadTask videoTask = videoRef.putFile(compressVideo.file);
//This is upload task StreamSubscription
final StreamSubscription<void> streamSubscription =
videoTask.snapshotEvents.listen((data) {
double uploadPer;
setState(() => uploadPer = (data.bytesTransferred / data.totalBytes)*
100);
print(uploadPer);
});
//When video uploading is completed then streamSubscription is cancel.
await videoTask.whenComplete(() => null);
streamSubscription.cancel();
//This is finally get video download URL
final String videoUrl = await videoRef.getDownloadURL();
print(videoUrl);
showToast("Upload Successful");

how do I create a progress bar in flutter firebase

I am having trouble in creating a progress bar to indicate the process of me uploading an image to firebase storage.
Future getImage(BuildContext context) async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
StorageReference firebaseStorageRef = FirebaseStorage.instance.ref().child('profile/${Path.basename(_image.path)}}');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_image);
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();
setState(() {
_imageURL = dowurl.toString();
});
print(_imageURL);
}
This is the code that I have written to upload the image and getting the image URL.
Hope someone can help me up thanks!
you can listen to the events on your uploadTask.
Here:
uploadTask.events.listen((event) {
setState(() {
_progress = event.snapshot.bytesTransferred.toDouble() /
event.snapshot.totalByteCount.toDouble();
});
}).onError((error) {
// do something to handle error
});
Now you can just display the progress like this:
Text('Uploading ${(_progress * 100).toStringAsFixed(2)} %')
To create a progress bar:
LinearProgressIndicator(
value: _progress,
)
Hope that helps.
The answer by Ayush Shekhar is correct, but outdated on some parts due to the rapid updating on firebase plugins.
On top of state class
double? _progress;
...
In the upload method, you can setup like this.
uploadTask.snapshotEvents.listen((event) {
setState(() {
_progress =
event.bytesTransferred.toDouble() / event.totalBytes.toDouble();
print(_progress.toString());
});
if (event.state == TaskState.success) {
_progress = null;
Fluttertoast.showToast(msg: 'File added to the library');
}
}).onError((error) {
// do something to handle error
});
You can get the download link like this.
uploadTask.then((snap) async {
final downloadURL = await snap.ref.getDownloadURL();
print(downloadURL);
});
...
Use the _progress in UI like this.
if (_progress != null)
LinearProgressIndicator(
value: _progress,
minHeight: 2.0,
color: Constants.primaryColor,
),
Use Future Builder and pass this getImage inside future builder Future Builder Example
or You can use Modal Progress HUD
Check this, it will work for both video and images:
final fil = await ImagePicker().pickVideo(source: ImageSource.gallery);
final file = File(fil!.path);
final metadata = SettableMetadata(contentType:"video/mp4");
final storageRef = FirebaseStorage.instance.ref();
final uploadTask = storageRef
.child("images/path/to/video")
.putFile(file, metadata);
// Listen for state changes, errors, and completion of the upload.
uploadTask.snapshotEvents.listen((TaskSnapshot taskSnapshot) {
switch (taskSnapshot.state) {
case TaskState.running:
final progress =
100.0 * (taskSnapshot.bytesTransferred / taskSnapshot.totalBytes);
print("Upload is $progress% complete.");
break;
case TaskState.paused:
print("Upload is paused.");
break;
case TaskState.canceled:
print("Upload was canceled");
break;
case TaskState.error:
// Handle unsuccessful uploads
break;
case TaskState.success:
print("Upload is completed");
// Handle successful uploads on complete
// ...
break;
}
});

Resources