Upload, Download, and Delete Images in AWS Amplify Storage with S3 Bucket in Flutter 2024
If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.
Table Of Contents::
Introduction
Flutter has become one of the most popular frameworks for building cross-platform applications, while AWS Amplify provides an easy and powerful way to add cloud capabilities to your applications. Among Amplify’s many features, Storage with S3 bucket is crucial for managing files like images, videos, and documents.
AWS Amplify storage module provides a simple mechanism for managing user content for your app in public, protected or private storage buckets. The storage category comes with built-in support for Amazon S3 (Simple Storage Service). In this blog, we’ll cover everything you need to integrate AWS Amplify Storage with S3 buckets into your Flutter app, step by step.
What is AWS Amplify Storage?
AWS Amplify is a cloud-based development framework by Amazon Web Services that simplifies building scalable, full-stack applications. The Amplify Storage category integrates with Amazon S3, allowing you to store and retrieve objects like images, audio, videos, and documents securely.
S3 Core Concepts
Amazon S3 stores data as objects within container buckets. An object consists of a file and optionally any metadata that describes that file. To store an object in Amazon S3, you upload the file you want to store to a bucket. When you upload a file, you can set permissions on the object and any metadata.
Buckets are the containers for objects. You can have one or more buckets. For each bucket, you can control access to it (who can create, delete, and list objects in the bucket), view access logs for it and its objects, and choose the geographical region where Amazon S3 will store the bucket and its contents.
Prerequisites
Before diving in, ensure you have the following ready:
- AWS Account: Sign up and Setup your AWS account
- Node.js: Required to install the Amplify CLI.
- Flutter Setup: Ensure Flutter and Dart are installed on your machine.
- Amplify CLI: Install globally using
npm install -g @aws-amplify/cli.
Configuration
Step 1: Initialize AWS Amplify
Install the Amplify CLI
Run the following command in your terminal:
npm install -g @aws-amplify/cli
This installs the Amplify Command Line Interface (CLI) globally.
Initialize the Amplify Project
Navigate to your Flutter project directory and run:
amplify init
- Choose Flutter as the framework.
- Configure your environment and backend details (e.g., name, environment, region, etc.).
- When prompted, provide the details of your application.
This command sets up Amplify for your project and generates the necessary files.
Step 2: Add the Storage Category
Run the following command to add storage:
amplify add storage
- Choose “Content (Images, audio, video, etc.)”.
- Define the resource name (or accept the default).
? Please select from one of the below mentioned services:
> Content (Images, audio, video, etc.)
NoSQL Database
? Please provide a friendly name for your resource that will be used to label this category in the project:
> mystorage
? Please provide bucket name:
> mybucket
- Set permissions for authenticated and unauthenticated users.
? Restrict access by?
> Auth/Guest Users
Individual Groups
Both
- Enable Auth/Guest access only if necessary (e.g., public-facing apps).
? Who should have access:
❯ Auth users only
Auth and guest users
Then you’ll be prompted to set the access scopes for your authenticated and (if selected prior) unauthenticated users.
? What kind of access do you want for Authenticated users?
> ◉ create/update
◯ read
◯ delete
? What kind of access do you want for Guest users?
◯ create/update
> ◉ read
◯ delete
- Push the changes to AWS:
amplify push
This command provisions an S3 bucket and configures it with the necessary policies.
Step 3: Add Dependencies to Your Flutter Project
In your Flutter app’s pubspec.yaml
file, add the following dependencies:
dependencies:
amplify_flutter: ^latest
amplify_storage_s3: ^latest
Run flutter pub get
to install the packages.
Step 4: Configure Amplify in Your App
To initialize the Amplify Auth and Storage categories, call Amplify.addPlugin()
for each plugin or pass all the plugins in Amplify.addPlugins()
. To complete initialization, call Amplify.configure()
.
Your code should look like this:
import 'package:flutter/material.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
import 'amplifyconfiguration.dart';
Future<void> _configureAmplify() async {
try {
final auth = AmplifyAuthCognito();
final storage = AmplifyStorageS3();
await Amplify.addPlugins([auth, storage]);
// call Amplify.configure to use the initialized categories in your app
await Amplify.configure(amplifyconfig);
} on Exception catch (e) {
safePrint('An error occurred configuring Amplify: $e');
}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await _configureAmplify();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AWS Amplify Storage with S3')),
body: Center(child: Text('Ready to upload files!')),
),
);
}
}
Step 5: Using StoragePath
You can use StoragePath
to access, upload to, or download from to any path in your S3 bucket. The Amplify Gen 1 CLI automatically creates the following directories:
public/
: Accessible by all users of your applicationprotected/<identityId>/
: Readable by all users (you need to specify the identityID of the user who uploaded the file). Writable only by the creating userprivate/<identityId>/
: Readable and writable only by the creating user
If you are using Amplify Gen2 or an S3 bucket not created by Amplify, you can use StoragePath to access, upload to, or download from any directory in your bucket.
You can specify the path to your S3 resource by creating a StoragePath
directly from a String, or by constructing the path with the user’s Cognito IdentityId.
A StoragePath
must:
- Not start with a ‘/’ (leading slash)
- Not be empty
Create a StoragePath from String
When constructing a StoragePath from a String, the provided string will be the path.
// Resolves to "public/exampleFile.txt"
const StoragePath.fromString('public/exampleFile.txt');
Create a StoragePath with user’s IdentityId
You may want to construct a StoragePath that contains the Amplify Auth user’s IdentityId. We’ve created a helper function that injects the user’s IdentityId when a Storage API is called, since fetching an IdentityId from the Auth plugin is not synchronous.
// If the user's identityId was "123",
// the StoragePath would resolve to "private/123/exampleFile.txt"
StoragePath.fromIdentityId(
(String identityId) => 'private/$identityId/exampleFile.txt',
};
Step 6: Implement Storage Functions
Upload a File to S3
To upload a Imagefile to S3 bucket, specify the file path and s3 bucket path where you want to store.
You can upload imageFile to a local directory using Amplify.Storage.
uploadFile
To upload Image:
From Local File Path (All Platforms)
Future<void> uploadImage(File imageFile) async {
try {
final result = await Amplify.Storage.uploadFile(
localFile: AWSFile.fromPath('imageFile.path'),
path: StoragePath.fromString('public/'+'your-s3-bucket-imagefile-path'),
);
print('Upload successful: ${result.key}');
} catch (e) {
print('Upload failed: $e');
}
}
From File (Mobile & Desktop)
import 'dart:io' show File;
Future<void> uploadImage(File imageFile) async {
try {
final result = await Amplify.Storage.uploadFile(
localFile: AWSFilePlatform.fromFile(imageFile),
path: const StoragePath.fromString('public/imagefile.png'),
).result;
safePrint('Uploaded imagefile: ${result.uploadedItem.path}');
} on StorageException catch (e) {
safePrint(e.message);
}
}
You can call this method with a selected file from your device.
Download a File from S3
You can download file to a local directory using Amplify.Storage.downloadFile
To download a file:
Future<void> downloadImage(String key, String downloadPath) async {
try {
final result = await Amplify.Storage.downloadFile(
path: StoragePath.fromString('public/'+'your-s3-bucket-imagefile-path'),
localFile: AWSFile.fromPath(downloadPath),
).result;
AWSFile awsFile = result.localFile;
path = awsFile.path!; //use this path to show your imagefile in your UI
print('Download successful: ${result.file.path}');
} catch (e) {
print('Download failed: $e');
}
}
This method saves the image file locally to the specified path.
Generate a download URL
You can get a downloadable URL for the image file in storage by its path.
When creating a downloadable URL, you can choose to check if the image file exists by setting validateObjectExistence
to true
in S3GetUrlPluginOptions
. If the file is inaccessible or does not exist, a StorageException
is thrown. This allows you to check if an object exists during generating the presigned URL, which you can then use to download that object.
Future<void> getDownloadUrl() async {
try {
final result = await Amplify.Storage.getUrl(
path: const StoragePath.fromString('public/example.txt'),
options: const StorageGetUrlOptions(
pluginOptions: S3GetUrlPluginOptions(
validateObjectExistence: true,
expiresIn: Duration(days: 1),
),
),
).result;
safePrint('url: ${result.url}');
} on StorageException catch (e) {
safePrint(e.message);
}
}
List Files in the S3 Bucket
You can list all files uploaded under a given path.
- This will list all public image files(i.e. those with
guest
access level):
Future<void> listAllImageFiles() async {
try {
final result = await Amplify.Storage.list(
path: const StoragePath.fromString('public/'),
options: const StorageListOptions(
pluginOptions: S3ListPluginOptions.listAll(),
),
).result;
safePrint('Listed items: ${result.items}');
} on StorageException catch (e) {
safePrint(e.message);
}
}
2. This will list all image files located under path album
that:
- have
private
access level - are in the root of
album/
(the result doesn’t include files under any sub path)
excludeSubPaths
can be used to exclude nested paths. /
is used by as the delimiter for nested paths. This can be customized with the delimiter
option.
Future<void> listAlbum() async {
try {
String? nextToken;
bool hasNextPage;
do {
final result = await Amplify.Storage.list(
path: const StoragePath.fromString('public/album/'),
options: StorageListOptions(
pageSize: 50,
nextToken: nextToken,
pluginOptions: const S3ListPluginOptions(
excludeSubPaths: true,
delimiter: '/',
),
),
).result;
safePrint('Listed items: ${result.items}');
nextToken = result.nextToken;
hasNextPage = result.hasNextPage;
} while (hasNextPage);
} on StorageException catch (e) {
safePrint(e.message);
}
}
Delete a File from S3
To delete a file:
Future<void> deleteImage(String path) async {
try {
await Amplify.Storage.remove(path: StoragePath.fromString(path));
print('Image deleted successfully: $key');
} catch (e) {
print('Delete failed: $e');
}
}
Best Practices
- Secure Access: Use Cognito for managing user access.
- Optimize File Handling:
- Use unique file keys to avoid overwrites.
- Compress images or videos before uploading.
3. Error Handling: Always handle exceptions to improve user experience.
4. Monitor Costs: Keep track of your S3 bucket usage to avoid unexpected costs.
Conclusion
Integrating AWS Amplify Storage with S3 buckets into your Flutter app is straightforward and highly beneficial for managing files. By following this guide, you can upload, download, list, and delete files seamlessly. Amplify also provides robust security and scalability, making it an excellent choice for modern applications.
Explore further to customize storage configurations, add advanced features like presigned URLs, or integrate other Amplify categories to build a comprehensive cloud-enabled app.
At What the Flutter, we love working with Flutter apps to make them high-performing and delight users. Contact us today to discuss how we can optimize your Flutter app performance.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Clap 👏 If this article helps you.
References:
Storage – Flutter – AWS Amplify Gen 1 Documentation
Learn more about how you can manage user content for your app in public, protected or private storage buckets using…docs.amplify.aws
Storage – AWS Amplify Gen 2 Documentation
Set up and connect to storage. AWS Amplify Documentationdocs.amplify.aws
Feel free to connect with us:
And read more articles from FlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.