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

692

Solution 1

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.

Solution 2

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)
Share:
692
Admin
Author by

Admin

Updated on December 27, 2022

Comments

  • Admin
    Admin over 1 year

    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?

  • Admin
    Admin about 3 years
    I haven't seen it rigth
  • progNewbie
    progNewbie about 3 years
    Does FirebaseStorage.instance.ref().child(path).getDownloadURL(); already trigger a 'read' of the quota?
  • osaxma
    osaxma about 3 years
    @progNewbie No, according to this answer.
  • gsm
    gsm about 3 years
    How can I control To control how long the image is cached in Firestore?