Making a Google Drive Clone | Flutter and AWS

VidaVolta
Flutter Community
Published in
7 min readOct 4, 2020

--

Let’s make a file-sharing application to show off what we can accomplish with Flutter and Amplify.

NOTE: Amplify Flutter is still in developer preview and is not recommended for production use at this time.

Introducing Doogle Grive

Our app will feature authentication powered by AWS Cognito, Storage powered by AWS S3, and Analytics powered by AWS Pinpoint. All integrated into our Flutter codebase using

Demonstration of the App

Background

What is Amplify?

Put simply, Amplify is a toolset that makes it easy (as in, one-click easy) to set up an AWS backend for your mobile application.

Why should I care?

Up until now, Flutter developers have been somewhat restricted to the Google ecosystem of backend resources. This has some pitfalls, particularly for people who are AWS aficionados or already have AWS deployed systems that they want to be integrated with a Flutter app.

With AWS officially supporting Amplify for Flutter, there is only room for growth in the Futter w/ AWS universe, so learning the fundamentals has some serious upside potential.

Setting up Amplify

For super-detailed installation instructions, check out this article I wrote on the topic. I’ll give you speedier instructions in this article.

  • Create an AWS account

Head over to the AWS portal and create an account under the ‘free’ plan.

  • Install the Amplify CLI

You will need flutter, node.js, npm, and git, then it is as simple as:

npm install -g @aws-amplify/cli@flutter-preview
  • Initialize your Flutter project

In the root directory of your flutter project, run:

amplify init

This will guide you through the setup process for your application. Once that is complete, run:

amplify add auth

amplify add analytics

amplify add storage

  • Configuration Code

Our application contains some code that adds the AWS plugins we want to use. In this case, we need Authentication, Analytics, and of course, Storage. All powered by our omnipresent pal in the sky — AWS.

If any of that confused you or gave you trouble, check out this video or this article (also made by me), or the official docs

Introducing the UI

Time to start coding. If you want to follow along, ‘checkout’ this commit in the repo.

This app is designed to make the AWS logic as clear as possible — so it is minimal in its design.

Login and Signup — using open-source for all its worth

The Login UI is built using the flutter_login package, which makes it super trivial to make an interactive user interface.

All we have to do is specify the callbacks to achieve the functionality we want. We will do this in the next part though.

Confirmation

Super-Confirmation Form

AWS Cognito will send a 6 digit confirmation code to the signup email, and upon entering this code the user is granted access to their account.

Bucket Viewer

The BucketViewer UI is all about displaying the cloud files that belong to the current user.

We will render each file on the UI as a Card , the end result looks something like this:

We have an icon representing the file type, the name of the file, and IconButtons for downloading and deleting the file.

Function to generate the file cards

TLDR: The widget is constructed using the cloud data (of typeStorageItem ), and the buttons trigger some more of our cloud functions called downloadFile anddeleteFile . Don’t worry, we will cover these soon.

Each of our files is displayed in a ListView widget, which gives us the scroll-ability we desire. The ListView widget is rendered by a FutureBuilder, which waits on the result of one of our trusty AWS API calls. Take a look at the final result and the UI code:

Scrollable File List

So our yet-to-be-revealed listFiles function creates a Future containing a List<StorageItem> , which in turn gets converted into a UI object when the Future is ready. When the UI is still waiting on the result of our function, an empty list is displayed.

One last thing, a handy logout button in the top right corner to log our user out.

Logout Button

Powering our UI with AWS

Authentication Functions featuring AWS Cognito

Our authentication service is provisioned using AWS Cognito, which is accessible via calls to Amplify.Auth.methodName . Let’s walk through the functions that power our authentication.

Sign Up

This is the first function used by a prospective user. We sign up using the name (in our case an email) and password submitted in our login form. It is simple, and it is supposed to be.

After signing up our first use, run amplify auth console to explore our Cognito managed user pool.

An unconfirmed user added to the user pool

We still need to confirm our user somehow, which segues us into…

Confirm

Pretty self-explanatory on this one. A confirmation code is sent to our user’s signup email and they enter it to activate their account.

Confirming our code

In your Cognito console, your user should now have the status of CONFIRMED.

Sign In

This is more or less the same as the signup. Note how we are keeping track of the results of our API calls using _isSignedIn and _isSignedUp to eventually decide what screen to send our user to after they are finished with our login page. I don’t show this function in this article, but check out the repo if you are curious.

Logout

We log our user out and then issue a call to pushReplacement to pop the current page of the stack and replace it with the Login page.

Upload File

There are a few important things that happen here.

First, we get the user that is currently logged in using the auth package in the call to getCurrentUser(). We use this username along with the filename to create a unique key for our file, then we upload it.

setState()and the uploading flag allow us to change the appearance of the upload-file button while our file is uploading. A small detail but a nice touch for our application.

Finally, we submit an analytics event to Amazon Pinpoint that tracks the number of bytes a user has uploaded.

Download File

First, we use DownloadsPathProvider to get the target directory for our download.

getUrl fetches the download URL for our file, which will expire after 1 hour because of the expires option in GetUrlOptions.

The calls to checkPermission and FlutterDownloader check the app’s download permissions and then downloads the file. For more details, check out the FlutterDownloader documentation or the GitHub repo for the full codebase.

Delete File

Deleting a file works in much the same way as adding a file, we use the item key to remove the file from the cloud. The calls to setState trigger a rebuild that populates the interface with an up-to-date file list.

List Files

Our storage bucket contains every single user’s files all stored in a bucket, meaning that they aren’t organized in any kind of database-like way.

Since we can’t query a bucket, we have to filter our files based on user.username . With a single command (line 7), we can filter the complete list of files into a list that contains only files that belong to the current user.

Remember the FutureBuilder UI from earlier? This list is the future — when it is ready, the UI draws all of our files.

RESULTS

Uploading a file works as expected.

Launch the analytics platform using amplify analytics console . For a more detailed look on using AWS analytics check out this article that I wrote.

The number of uploaded bytes are being tracked in Amazon Pinpoint

Future Work

Going from a bucket to a datastore is the next logical evolution of this app. Adding a feature to give another user (referenced by email) access to a particular file would also be a useful addition

Acknowledgments and Sources

https://www.twitter.com/FlutterComm

--

--