FlutterArticles
Posted on September 10, 2020
Flutter Apps with AWS Amplify Backend: Part 4 — Storage
Manage user content using Amazon S3
What is Amplify Storage?
The Amplify Storage category provides an interface for managing user content for your app in […] storage buckets. The Storage category comes with default built-in support for Amazon Simple Storage Service (S3).
NOTE: Amplify Flutter is still in developer preview and is not recommended for production use at this time.
What Will We Be Making?
In this tutorial, we will be creating a simple application that uses the basic features of Amplify Storage. We will be able to upload an image, download it, and delete it using the Amplify API.
Prerequisites
The only thing you need for this tutorial is the app you created in Part 1 of this tutorial series.
If you don’t want to read part 1 and you are already familiar with Amplify Flutter, then simply create a new Flutter application and connect it to a cloud instance of Amplify.
Let’s Dive In
Create a Basic Amplify Project
If you are using the app you created in Part 1, you can skip this step.
Otherwise, create a new flutter project, and from the project directory run:
amplify init
Setup the Backend
The backend can be set up entirely through the amplify cli:
amplify add storage
Follow the setup wizard to add storage to your application
Checking on our resources
To check on our project’s cloud resources, run:
amplify console
This will launch your project’s console in your browser.
Authentication and File storage are configured for our project
Integrate Storage Features
Add the amplify packages to your pubspec.yaml.
dependencies:
file_picker: '^1.8.0+1'
amplify_core: '<1.0.0'
amplify_auth_cognito: '<1.0.0'
amplify_storage_s3: '<1.0.0'
Next, include the necessary packages in your main.dart file:
import 'package:file_picker/file_picker.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
Initializing Amplify Storage
If you don’t want to be bored with the specifics of setting up this application from scratch, take a look at the gist here or the repo for the completed code.
First, let’s set up a barebones main.dart for you to work with:
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
import 'amplifyconfiguration.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isAmplifyConfigured = false;
String _uploadFileResult = '';
String _getUrlResult = '';
String _removeResult = '';
Amplify amplify = new Amplify();
@override
void initState() {
super.initState();
configureAmplify();
}
void configureAmplify() async {
// First add plugins (Amplify native requirements)
AmplifyStorageS3 storage = new AmplifyStorageS3();
AmplifyAuthCognito auth = new AmplifyAuthCognito();
amplify.addPlugin(authPlugins: [auth], storagePlugins: [storage]);
// Configure
await amplify.configure(amplifyconfig);
setState(() {
_isAmplifyConfigured = true;
});
}
void _upload() async {
}
void getUrl() async {
}
void _download() async {
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Amplify Flutter Storage Application'),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
RaisedButton(
onPressed: _upload,
child: const Text('Upload File'),
),],
),
),
),
);
}
}
As always, we want to configure our Amplify plugin. The only thing different between the previous tutorials is which plugins we will be adding. In this case, we want both AmplifyStorageS3 and AmplifyAuthCognito.
Uploading Files
To upload a file from your computer to your emulated device, simply drag and drop a file over the emulator.
You will also need to implement your _upload() function as follows:
void _upload() async {
try {
print('In upload');
File local = await FilePicker.getFile(type: FileType.image);
final key = 'ExampleKey';
Map<String, String> metadata = <String, String>{};
metadata['name'] = 'vennify_logo';
metadata['desc'] = 'A photo of the vennify logo';
S3UploadFileOptions options = S3UploadFileOptions(
accessLevel: StorageAccessLevel.guest, metadata: metadata);
UploadFileResult result = await Amplify.Storage.uploadFile(
key: key, local: local, options: options);
setState(() {
_uploadFileResult = result.key;
});
} catch (e) {
print('UploadFile Err: ' + e.toString());
}
}
This will upload a file to the cloud with the key ‘ExampleKey’ which we can use later to download or interact with the file.
‘ExampleKey’ file (our logo image) has been successfully added to our bucket
Downloading Our File
Okay, so we have a file now in our S3 bucket. Let’s say we want to render this image in our app. There are a couple of ways to do this, but for now, I will show you the easier of the two.
void _getUrl() async {
try {
print('In getUrl');
String key = "ExampleKey";
S3GetUrlOptions options = S3GetUrlOptions(
accessLevel: StorageAccessLevel.guest, expires: 10000);
GetUrlResult result =
await Amplify.Storage.getUrl(key: key, options: options);
setState(() {
_getUrlResult = result.url;
});
} catch (e) {
print('GetUrl Err: ' + e.toString());
}
}
The _getUrl() *function basically searched through our S3 bucket for a file with the key ‘ExampleKey’ and fetches the URL for this file. Using this URL, we can then load the image. In our example, once the URL is fetched, *setState() *is called, which rebuilds a *NetworkImage in our widget tree, thus displaying our photo.
Don’t forget to add a button that executes *getUrl() *when pressed. You can always take a look at the repo if you are just interested in the completed code.
Pretty cool right? In your implementation, you may want to obtain the key (in this case it is hardcoded as ExampleKey) differently.
Deleting Files
Deleting files is very similar to uploading them. Like most of these storage functions, you interact with your files based on their key. Therefore, to delete a file in your bucket you just need its key.
void remove() async {
try {
String key = "ExampleKey";
RemoveOptions options =
RemoveOptions(accessLevel: StorageAccessLevel.guest);
RemoveResult result =
await Amplify.Storage.remove(key: key, options: options);
setState(() {
_removeResult = result.key;
});
print('_removeResult:' + _removeResult);
} catch (e) {
print('Remove Err: ' + e.toString());
}
}
Moving Forward
Congratulations! You now have covered all of the basics of storage using S3, and if you have read the other parts of this series, you have also dabbled with Analytics using Pinpoint and Authentication with Cognito.
Now that we have the basics pinned down, future articles will feature a combination of these services to create more fully-featured applications.
This Series
Part 1: Basic Setup
Part 2: Authentication
Part 3: Analytics
Part 4: Storage
Posted on September 10, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.