Flutter Apps with AWS Amplify Backend: Part 4 — Storage
Tags: flutter, amplify, aws, android
Published: 2020-09-10 00:38:36


# 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.

![Example Usage of App](https://cdn-images-1.medium.com/max/2000/1*UKevYxnftTOtySJKAG49CA.gif)*Example Usage of App*

## 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.](https://docs.amplify.aws/start/getting-started/setup/q/integration/flutter)

## 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](https://cdn-images-1.medium.com/max/2090/1*iTosYJEoYRr4GiS3SmHJ6g.png)*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](https://cdn-images-1.medium.com/max/3826/1*OAUX-aeJo1aiF5vw2Rb-WQ.png)*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](https://gist.github.com/adamfillion/fbb6ee45674cc4a1124eb77996a4a722) here or the [repo](https://github.com/Vennify-Inc/flutter-amplify-tutorial/tree/4e05b86310591025424eef9e526e1fc0b8cec07f) for the completed code.

First, let’s set up a barebones main.dart for you to work with:

```dart
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.

![](https://cdn-images-1.medium.com/max/2000/1*1pOel3SDYz0mBZ3IziKcWQ.gif)

You will also need to implement your *_upload()* function as follows:

```dart
  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](https://cdn-images-1.medium.com/max/3670/1*boIRCTQsYxDruysa518Kfw.png)*‘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.

```dart

  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.

![](https://cdn-images-1.medium.com/max/2000/1*YHa03MlCYCxA4zrl5MDyuA.gif)

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.

```dart

  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](https://medium.com/@vennify.education/flutter-apps-with-aws-backend-part-1-basic-setup-7e1dd53e9161)

**Part 2:** [Authentication](https://medium.com/@vennify.education/flutter-apps-with-aws-backend-part-2-authentication-a66136f23995)

**Part 3:** [Analytics](https://medium.com/@vennify.education/flutter-apps-with-aws-backend-part-3-analytics-bdb8b5bad5c0)

**Part 4:** [Storage](https://medium.com/@vennify.education/flutter-apps-with-aws-backend-part-4-storage-74ae2dbdc4b5)