Faz
Faz

Reputation: 359

Load and cache images from AWS S3 into flutter

I want to fetch and cache user profile pictures from S3 into my flutter app.

First, when a user uploads a picture, my flask backend generates a random file name, stores the file in an S3 bucket (using boto3) and the name in the database.

To retrieve the picture I use presigned_urls:

s3client = boto3.client('s3', config=Config(signature_version='s3v4', region_name='eu-west-2'))
s3client.generate_presigned_url('get_object',Params={'Bucket': BUCKET,'Key': file_name_retrieved_from_db_for_user},ExpiresIn=120)

In Flutter I have a Future which calls the API and gets the image's generated presigned url (i.e. https://xx.s3.amazonaws.com/FILENAME.jpg?signature).

And then using a FutureBuilder I do the following:

FutureBuilder(
                                    future: get_picture_url(user_id),
                                    builder: (context, snapshot) {
                                      if (snapshot.connectionState == ConnectionState.done) {
                                        if (snapshot.data==0) {
                                          return Icon(Icons.account_circle, size: 110.0);
                                        }
                                        print(user_id);
                                        print('this is the data fetched');
                                        print(snapshot.data);
                                        return CachedNetworkImage(
                                          imageUrl: snapshot.data,
                                          imageBuilder: (context, imageProvider) => Container(
                                            width: 180.0,
                                            height: 180.0,
                                            decoration: BoxDecoration(
                                              shape: BoxShape.circle,
                                              image: DecorationImage(
                                                image: imageProvider, fit: BoxFit.cover),
                                              ),
                                          ),
                                          placeholder: (context, url) => ProfPicPlaceHolder(),
                                          errorWidget: (context, url, error) => Icon(Icons.error),
                                      );
                                      } else {
                                        return ProfPicPlaceHolder();
                                      }
                                    }
                                    ),

The problem is that each time the FutureBuilder calls the API to get the image's url, the URL is different due to different signature following the filename in the url, so the same image is loaded and cached again and again.

How can I access an image that is stored in S3 in flask using boto3 and then pass that url to cached network image in flutter? Is there any other way to cache an image in flutter from aws S3?

Upvotes: 2

Views: 2464

Answers (2)

Pedro Brasil
Pedro Brasil

Reputation: 53

Adding to your solution, I create a simple function getAWSS3BaseImageUrl

String getAWSS3BaseImageUrl(String fullUrl) {
  RegExp regExp = RegExp(r'(^[^?]+)');
  Match? match = regExp.firstMatch(fullUrl);
  return match?.group(1) ?? '';
}

And use it across the application to generate the cacheKeyvalues to use in both CachedNetworkImage and CachedNetworkImageProvider instances.

Examples

CachedNetworkImage(
    imageUrl: yourURL,
    cacheKey: getAWSS3BaseImageUrl(yourURL),
),

or

CachedNetworkImageProvider(
    yourURL,
    cacheKey: getAWSS3BaseImageUrl(yourURL),
),

Upvotes: 1

Faz
Faz

Reputation: 359

I implemented a solution. For those dealing with the same thing, use the property cacheKey of the CachedNetworkImage(). I used the filename (stored in user's table) as cacheKey. Also, I cache filename and file url in a hivebox which is updated regularly. My view reads data from the hivebox.

Upvotes: 2

Related Questions