Cloud storage is a powerful tool if your app needs to upload photos, videos, documents, or just about any other file. This is especially useful if your app needs features such as profile pics, file attachments, or even just dynamically changing homepage content.

Firebase Cloud Storage is especially good for indie developers because of its free spark plan which gives you 5GB of storage for free with upgradeable plans too.

The documentation for using Firebase Cloud Storage with native Android or iOS is strong, but the same can’t be said for Flutter.

In fact, as of the time of writing this, there isn’t any dedicated documentation for this other than the library’s pub page and the source code. This makes it hard to learn how to do even simple operations like downloading an image from storage.

Thus in this article, we’ll go through how to both upload and download files in a couple different ways.

Installation

First ensure that you’ve connected your app to Firebase.

Then add this to your pubspec.yaml file.

dependencies:
  firebase_storage: ^3.0.8

Then install it from the command line as you do.

$ flutter pub get

Finally, import it into your dart file.

import 'package:firebase_storage/firebase_storage.dart';

Once that’s done, you can get a reference to your Storage

StorageReference storageReference = FirebaseStorage().ref();

Uploading Files

Flutter doesn’t have all the same Firebase Storage capabilities as native Android and iOS. It does however, have the important bits.

To be specific, I’m talking about the putData and putFile methods.

For this part of the tutorial, I’ll be using the image_picker library.

PutData

var image = await ImagePicker.pickImage(source: ImageSource.gallery);
var bytes = await image.readAsBytes();

var uploadTask = storageReference
    .child("samples")
    .child("testimage")
    .putData(bytes);

var storageSnapshot = await uploadTask.onComplete;
var url = await storageSnapshot.ref.getDownloadURL();

We’re getting an image from the gallery as a file, converting it to bytes, then passing that into putData. We append child onto storageReference to navigate through our directories in storage. The last child becomes the filename of the uploaded image.

Note that this will work for any file, not just images. If you find that your file isn’t being uploaded with this simple code, try checking your Storage Security Rules.

PutFile

var image = await ImagePicker.pickImage(source: ImageSource.gallery);

var uploadTask = storageReference
    .child("samples")
    .child("testimage")
    .putFile(image);

var storageSnapshot = await uploadTask.onComplete;
var url = await storageSnapshot.ref.getDownloadURL();

Admittedly, the byte conversion earlier was redundant. We could’ve entirely skipped that step and use putFile instead. Everything else remains the same.

PutFile is the most widely used method for uploading images. It’s simply just that easy to use.

Downloading Files

Just like with uploading, Flutter doesn’t have the same capabilities as its native counterparts but rather, just the important bits.

Flutter Firebase Cloud Storage has the getData and writeToFile methods. On top of those, there’s one more way of displaying images which is something only Flutter can do so easily.

GetData

final ONE_MEGABYTE = 1024 * 1024;

var imageInBytes = await storageReference
    .child("samples")
    .child("testimage")
    .getData(ONE_MEGABYTE);

GetData takes in the parameter of the max size it will allow itself to get. If it attempts to download a file larger than this, it’ll throw an exception.

While this in itself is simple enough, you can’t do too much with a file in byte format.

WriteToFile

var imageRef = storageReference
    .child("samples")
    .child("testimage");

final Directory tempDir = Directory.systemTemp;
final File tempImageFile = File('${tempDir.path}/samplefilepath');
final StorageFileDownloadTask downloadTask = imageRef.writeToFile(tempImageFile);
downloadTask.future.then((snapshot) =>
    setState(() {
      _image = tempImageFile;
    }));

This method is especially useful if you need to save the file or use it for similar file-use-cases. I wouldn’t call this recommended method for downloading and displaying images if you’re not saving them. Not for Flutter at least.

Image.network (with Download URL)

var downloadUrl = await storageReference
    .child("samples")
    .child("testimage")
    .getDownloadURL();

setState(() {
  _imagePath = downloadUrl;
});

// Somewhere in your scaffold
Image.network(_imagePath);

Suddenly, things get a lot simpler. Image.network is one of my favourites things about Flutter because of how simple it is.

Sure, Android can display images off of network URLs as well, but this often either requires a good image library or lots of boilerplate code if you’re trying to achieve it with the native SDK.

These aren’t the only ways

Firebase Storage for Flutter doesn’t have as many ways to upload and download files from the library itself. It’s missing the getStream method for example. Flutter however, is well powerful enough to make the most out of the library’s limited functionality.

These are by no means the only ways to use Firebase Storage with Flutter. As with many things in the software development world, these methods are limited only by your skill, experience, and creativity.

Newsletter

Subscribe to the Newsletter