How To Use Firebase Storage in Flutter

Peter
Firebase Tips & Tricks
8 min readMay 6, 2020

Note: This post was originally published on May 2020 and has been completely revamped and updated for accuracy and comprehensiveness.

In this article, we will use Firebase Storage to add images, retrieve them, and we will also connect the images with Firestore.

This is the fifth article related to Firebase in Flutter, you can check the previous articles in the below links:

To know how to download the google-service.json file, you can check the first article in the above list. In this article, I will add images to the assets folder, so we can then add those images to Firebase Storage, link them with Firestore and then retrieve those images, and we will also use the image picker plugin to get an image from gallery and save it to Firebase Storage.

Note: You can find the source code for all the Firebase/Flutter tutorials in the following repository: Firebase-Flutter-tutorials. Support me by starring the repository and following me on Github for more awesome content! You can also subscribe to my newsletter and join me at Discord! Let’s get started 😁

Add Firebase Storage To Flutter

As I said before, to check how to create a flutter project and add the google-service.json file which is used for android, then please check this article Get Started With Firebase in Flutter. Next, you need to add the following dependency to the pubspec.yaml file:

dependencies:
firebase_core: ^1.0.3
cloud_firestore: ^1.0.4
firebase_storage: ^8.0.3

Click CTRL + S to save, and you have successfully added Cloud Firestore + Firebase Storage to your Flutter application!

⚠️⚠️Important Note⚠️⚠️: This tutorial is written using null safety, therefore when you create a project execute dart migrate --apply-changes to migrate to null safety.

Also, since we are not using Firebase Authentication, you need to change the rules for Firebase Storage to public:

But only use the above rules in the development phase and not in production.

Note : I would advise to read the previous articles related to Firebase with Flutter before this one.

Adding Images to Flutter

So, since we are going to use images inside the assets folder and add them to Firebase Storage, therefore first we can create a folder called images under the assets folder and inside the images folder we can add the images:

Then to access them inside the Flutter application, we need to declare them inside the pubspec.yaml:

# To add assets to your application, add an assets section, like this:
assets:
- assets/images/

Now, you can access all images inside the assets/images/ in your application.

Implementing Multiple Select in GridView

To display those images inside the Flutter application, we can use a gridView widget. So first inside the main.dart file, create a StatelessWidget that will call a StatefulWidget:

So main() method will be called first and, it will call the runApp() method which will take a widget and make it the root widget. The build() method will contain the layout of the application. The home property will take a widget, in this case we created a StatefulWidget called myHomePage. Then we need to declare this widget:

So myHomePage extends StatefulWidget, we override the method createState and create a State class called _myHomePageState. In the State class we declare the following variables:

We first create an instance of FirebaseStorage:

Also, we create a list of images, that will contain our images. The State class contains the initState() method which is called once when the StatefulWidget is loaded, therefore override the initState() method:

getImages() will retrieve all the images inside the assets/images directory and adds them all to the listOfImage. Then inside the build() method we add the GridView.builder widget:

So here the itemCount will take the number of images inside the list. The SliverGridDelegateWithFixedCrossAxisCount will design the gridView so on every line we will have 3 images. The mainAxisSpacing and the crossAxisSpacing is the number of logical pixels between each child.

Creating The GridView

So now inside the callback (BuildContext context, int index), we return a GridTile widget:

Let’s explain step by step here, first the GridTile takes a Material child, and then the Material widget takes a GestureDetector widget, which we will use to detects gestures. Then inside the GestureDetector widget, we use the onTap property:

So inside the onTap() we use the setState() which will rebuild the layout by calling the build() method. We first check if the listOfStr contains the image, if it does then we remove it from the list, and if it doesnt contain then we add it to the list.

So here the user is tapping on the image, if the image is already tapped then it is inside the list, if the user taps again then we remove it from the list and build again. Now we use the child Stack inside the GestureDetector. The reason we use Stack is because we want to add an icon if the user chose an image. We also use the ternary operator to check if the image is inside the list or not. Check the image below, to see how the layout would be:

So as you can see, when we select an image, we use the Opacity widget and decrease the opacity and we also add a check icon.

Adding Images to Firebase Storage

So to add the selected images to Firebase Storage, we can create a ElevatedButton to save the images to storage:

We wrap the ElevatedButton inside a Builder because we want to use a Snackbar later, which contains Scaffold.of(context), without the Builder method then the Scaffold widget will not be inside the context.

So since we might select multiple images, then we iterate inside the listOfStr and retrieve the name of the images, then we get the temporary directory inside the phone OS. We also use the rootBundle which is a top level property inside the AssetBundle and we use load() to retrieve a binary resource from the asset bundle as a data stream. After that we create a new file inside the temporary directory, and we write the bytes to the file. Then we can finally save the images to Firebase Storage:

TaskSnapshot snapshot = await storage
.ref()
.child("images/$imageName")
.putFile(file);

ref() will give you a reference to Firebase Storage, child() will create a folder called images and inside of the folder we will have all the images, lastly putFile() will take the file as an argument and add it to Firebase Storage. We use await to wait until it adds the image to storage and then continue execution.

Linking Firebase Storage With Firestore

After calling putFile() method, we can check if the image were successfully added or not:

If there is no error, then we successfully added the image to Firebase Storage, we can then use getDownloadUrl() which returns Future<dynamic> and thats why we use await. The getDownloadUrl() will give us the url of the image inside Firebase Storage. After that we can finally add both the url and the image to Firestore, inside the images collection. We also assign isLoading to false to stop the CircularProgressIndicator() from loading. The CircularProgressIndicator() is used inside the Column widget:

isLoading
? CircularProgressIndicator()
: Visibility(visible: false, child: Text("test")),

Retrieving Images From Firestore

So, to retrieve the images we create another ElevatedButton:

onPressed of the button we, navigate to the SecondPage. Therefore we create another dart file and call it second_page.dart. Inside the State class in the we retrieve an instance of Firestore:

final FirebaseFirestore fb = FirebaseFirestore.instance;

Then we use a FutureBuilder to get the images and add them in a listView:

So in the FutureBuilder we use the method getImages() which will return all the documents inside the collection images. Then we use the ConnectionState, if the connectionState is equal to done, then the asychronous operation is finished. If it is equal to none then the operation finished but didnt return anything. Outside the if/else we return CircularProgressIndicator(); which will before getting the result from the Future.

Using Image Picker Plugin

The second way to add images to Firebase Storage, is to get an image from the gallery, so to do that, navigate to the pubspec.yaml file and add the following dependency:

image_picker: ^0.7.4

Then in the second_page.dart, add a ElevatedButton below the FutureBuilder:

ElevatedButton(child: Text("Pick Image"), onPressed: getImage)

onPressed it will call the method getImage:

The getImage() method will get an image from gallery, and call setState to rebuild the layout. Therefore under the ElevatedButton we add the image:

_image == null
? Text('No image selected.')
: Image.file(
_image,
height: 300,
),

Under the image, we create a ElevatedButton and save the data to Firebase Storage under folder image:

Deleting an Image

Now, let’s say you have users in your application, each user will have a profile image, if a user gets deleted then you want to delete the image also from Firebase Storage. In that case you can do the following, for example:

Using getReferenceFromUrl() you will get URL pointing to a Firebase Storage location, and then you can call delete().

You can find the source code here: Firebase Storage Tutorial

I hope you enjoyed this Flutter/Firebase article, in the next article I will use Firebase messaging.

Originally published at https://petercoding.com on May 6, 2020.

--

--

Peter
Firebase Tips & Tricks

Software Developer. Actively helping users with their Firebase questions on Stack Overflow. Occasionally I post on medium and other platforms.