Connecting AWS Amplify with Flutter projects

Muhammed Salih Guler
Flutter Community
Published in
10 min readJun 30, 2022

Previously, you set up your computer to use AWS Amplify. Now it is time to set up the project to build up the ground work.

In the span of this blog post series, you will be learning:

Creating a new Flutter project from Flutter CLI tool

Once you have your Flutter setup ready, you can create your project either from the IDE of your choice by using Flutter plugins, or you can take advantage of the Flutter’s CLI tool and create a project there as well. To prevent picking sides on the IDE war, create a new Flutter project using the terminal.

First, make sure you are on your project’s root folder. After that run the following command:

flutter create --org com.yourcompany -i swift -a kotlin \
--description 'A Flutter application to test SMS flows of Amplify' amplify_sms_test

This command will pick the Swift for iOS development, Kotlin for Android development (right now they are default languages for project creation) and create a project for com.yourcompany organization.

Keep in mind that organization and the application name should be unique if you are planning to publish this application.

Once you run the command, you will be seeing a set of messages to let you know that the app is created.

msalihg projects % flutter create --org com.yourcompany -i swift -a kotlin \
--description 'A Flutter application to test SMS flows of Amplify' amplify_sms_test
Signing iOS app for device deployment using developer identity: "Apple Development: <Apple user name>"
Creating project amplify_sms_test...
Running "flutter pub get" in amplify_sms_test... 1,343ms
Wrote 127 files.
All done!
In order to run your application, type:
$ cd amplify_sms_test
$ flutter run
Your application code is in amplify_sms_test/lib/main.dart.

Final step is to update the minimum supported versions of the Flutter project:

  • For Android you need to set the minimum SDK version to 21 or more. From your project root, navigate to the android/app/ directory and modify build.gradle using a text editor of your choice.
minSdkVersion 21
  • For iOS navigate to the ios/ directory and modify the Podfile using a text editor of your choice by updating the line starting with platform :ios, with platform :ios, '11.0'

Initializing AWS Amplify for your Flutter project

Now that you have a Flutter project and an AWS account that you can use, now you can start to bring the pieces of the puzzle together. First step, initializing the AWS Amplify to your Flutter project.

First go to the folder of your application by using command line tool:

cd /<path-to-the-project>/amplify_sms_test

Afterwards, run the following command in your terminal to initialize your Amplify project.

amplify init

This will bring a couple of configuration questions. Answer them according to your configuration settings. If there is a recommendation for you, it will be stated with parentheses next to the question and you can simply click Enter to move forward:

msalihg amplify_sms_test % amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project (amplifysmstest)

After that Amplify CLI will recommend you some settings to make your setup easier for you:

The following configuration will be applied:Project information
| Name: amplifysmstest
| Environment: dev
| Default editor: Visual Studio Code
| App type: flutter
| Configuration file location: ./lib/
? Initialize the project with the above configuration? (Y/n)

You can either accept the recommended settings or reject it and enter all settings by yourself. E.g. if your default editor is not VS Code, then you can reject these settings and pick your settings by yourself:

? Initialize the project with the above configuration? No
? Enter a name for the environment dev
? Choose your default editor:
Xcode (macOS only)
Atom Editor
Sublime Text
❯ IntelliJ IDEA
Vim (via Terminal, macOS only)
Emacs (via Terminal, macOS only)
None
(Move up and down to reveal more choices)
? Choose the type of app that you are building flutter
Please tell us about your project
? Where do you want to store your configuration file? ./lib/

Once it is done, you are expected to pick an authentication method:

? Select the authentication method you want to use: (Use arrow keys)
❯ AWS profile
AWS access keys
For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
? Please choose the profile you want to use (Use arrow keys)
❯ default

This will initialize your project for you, just sit back and relax in the meantime.

Adding Amplify libraries and initializing auth flow

First thing that you need to do is to delete everything in the main.dart file. You will build everything from scratch.

You will start off by adding the amplify libraries and configuring those. Run the following command at your project’s root path:

> flutter pub add amplify_flutter

This will add set of functions for you to configure Amplify from your application.

Next step is to add authentication library to the application:

> flutter pub add amplify_auth_cognito

Once you have the libraries, add the auth functionality to the configurations of the Amplify CLI:

Keep in mind that, the type of username used for signing in cannot be changed after creating a user pool (after running the command below once). If needed, first run amplify remove auth to delete the existing user pool, then follow the New Project flow on this page for enabling phone-number sign-in.

> amplify add auth

The command above will take you through the setup process of the authentication capabilities. Follow each step as shown below:

? Do you want to use the default authentication and security configuration? (Use 
arrow keys)
❯ Default configuration
Default configuration with Social Provider (Federation)
Manual configuration
I want to learn more.
? Warning: you will not be able to edit these selections.
? How do you want users to be able to sign in?
Username
Email
❯ Phone Number
Email or Phone Number
I want to learn more.
? Do you want to configure advanced settings? No, I am done.
✅ Successfully added auth resource amplifysmstestcd876b37 locally

After this, your changes are still considered to be on the local machine of yours. You need to push and publish your changes to your AWS account. For this, you will use the following command:

# Builds all your local backend resources and provision it in the cloud
> amplify push

Building the UI of the application

If you do not want to build the UI of your application for the authentication flow, you can always use the Authenticator library from AWS Amplify.

Now your application is ready to handle phone number as username property in the sign in method. By default, email verification is enabled. If you would also like to use phone numbers for verifying users’ accounts, stick around here and you will learn about it as well.

It is time to start off writing some code! First call your main function to start your application:

import 'package:flutter/material.dart';//TODO: Create SMSFlowExampleApp
void main() => runApp(const SMSFlowExampleApp());

Afterwards, create a StatelessWidget called SMSFlowExampleApp to have your application level settings.

class SMSFlowExampleApp extends StatelessWidget {
const SMSFlowExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorSchemeSeed: Colors.orange,
useMaterial3: true,
),
//TODO: Create SignUpScreen
home: const SignUpScreen(),
);
}
}

One thing to notice here is that, you are enabling the new Material Design properties to use in your application. This way you can have a nice and modern look to your application.

Next step is to add SignUpScreen:

class SignUpScreen extends StatelessWidget {
const SignUpScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Amplify SMS Flow'),
),
//TODO: Remove below and create text input fields
body: const SizedBox.shrink(),
);
}
}

Now it is time for creating your text fields to enter information:

class OutlinedAutomatedNextFocusableTextFormField extends StatelessWidget {
const OutlinedAutomatedNextFocusableTextFormField({
this.padding = const EdgeInsets.all(8),
this.obscureText = false,
this.labelText,
this.controller,
this.inputType,
Key? key,
}) : super(key: key);
final String? labelText;
final TextEditingController? controller;
final TextInputType? inputType;
final EdgeInsets padding;
final bool obscureText;

@override
Widget build(BuildContext context) {
return Padding(
padding: padding,
child: TextFormField(
controller: controller,
obscureText: obscureText,
keyboardType: inputType,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: labelText,
),
),
);
}
}

This text field will be a highly specific one. Once it is focused, it will automatically focus on to the next item when users submit the text.

Now use this widget alongside with a button to collect the user information for signing them up! Update the body in the SignUpScreen with the following:

ListView(
children: [
const OutlinedAutomatedNextFocusableTextFormField(
labelText: 'Phone Number',
inputType: TextInputType.phone,
),
const OutlinedAutomatedNextFocusableTextFormField(
obscureText: true,
labelText: 'Password',
),
const OutlinedAutomatedNextFocusableTextFormField(
labelText: 'E-mail address',
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
//TODO: Update with functionality
onPressed: () {},
child: const Text('Sign Up'),
),
),
],
),

Now if you run your application on a device, you should see a view similar to below:

All elements are wrapped with a ListView to embrace the fact that with keyboard is enabled or on smaller devices the fields can take much more place than you can allocate and being scrollable can help you wrap all view to be accessible to the users.

You will not be learning about form validation here. If you want to learn about form validation, you can check the Flutter documentation for a tutorial.

There are couple of ways to get the written text from the fields. You can get it by onFieldSubmitted or onChanged but these will require some additional work for us to keep the data. More straightforward approach is to use a TextEditingController. It is a special ValueNotifier to keep a reference to any changes that is happening in a text input field and gives you access to the current text in the field any time you need it.

First thing you need to is to turn the SignUpScreen to a StatefulWidget. You can take advantage of your IDE for that. Go over the StatelessWidget text and show the options. That will help you to convert your widget in to a StatefulWidget.

You have converted this widget into a StatefulWidget because ValueNotifier or ChangeNotifier are Listenableobjects notify any changes and pass it to its subscribers. Once they are created, they start to be active and they need to be disposed when they are not used. For this purpose, you will override the dispose method of the StatefulWidgetand only assign the values in the initState method:

class _SignUpScreenState extends State<SignUpScreen> {

late final TextEditingController _phoneNumberController;
late final TextEditingController _passwordController;
late final TextEditingController _emailController;

@override
void initState() {
super.initState();
_phoneNumberController = TextEditingController();
_passwordController = TextEditingController();
_emailController = TextEditingController();
}

@override
void dispose() {
_phoneNumberController.dispose();
_passwordController.dispose();
_emailController.dispose();
super.dispose();
}
...
}

Now assign those into the text input fields that you created before:

OutlinedAutomatedNextFocusableTextFormField(
controller: _phoneNumberController,
labelText: 'Phone Number',
inputType: TextInputType.phone,
),
OutlinedAutomatedNextFocusableTextFormField(
controller: _passwordController,
obscureText: true,
labelText: 'Password',
),
OutlinedAutomatedNextFocusableTextFormField(
controller: _emailController,
labelText: 'E-mail address',
),

Last step before you pull in the Amplify topics is to get the texts from the fields. At onPressed method of the button that you created, get all the texts and be ready to use them:

...
onPressed: () {
final phoneNumber = _phoneNumberController.text;
final password = _passwordController.text;
final email = _emailController.text;
if (phoneNumber.isEmpty || password.isEmpty || email.isEmpty) {
debugPrint('One of the fields is empty. Not ready to submit.');
} else {
debugPrint('All fields are filled. Ready to submit.');
}
},
...

Adding Amplify Flutter library components

Now it is time to pull in the Amplify libraries:

// Add the following imports next to the others
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'amplifyconfiguration.dart';class _SignUpScreenState extends State<SignUpScreen> {
...
Future<void> _configureAmplify() async {
final auth = AmplifyAuthCognito();

// Use addPlugins method to add more than one Amplify plugins
await Amplify.addPlugin(auth);

await Amplify.configure(amplifyconfig);
}
...
}

The _configureAmplify method adds the plugins that you are going to be using in your application and configure it for the Amplify libraries. You can name the method to anything that you would like and configure it the way that your application needs.

Adding a plugin is an asynchronous operation, you may call it at any place that you want. You can call it at the initState just before your UI is drawn or you can call it with helper widgets such as FutureBuilder to handle the different states.

Go to your ListView that you have created before and wrap that widget with a FutureBuilder:

FutureBuilder<void>(
future: _configureAmplify(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView(...);
} if (snapshot.hasError) {
return Text('Some error happened: ${snapshot.error}');
} else {
return const Center(child: CircularProgressIndicator());
}
}
),

Next step is wiring up the sign up flow with phone number.

For more information about the AWS Amplify authentication libraries you can check the official documentation, ask your questions at Amplify Discord. You can also check the source code for this over GitHub and if you have any questions regarding to the Amplify and Flutter topics, send it to me via DM on Twitter!

See you in the next post!

Follow Flutter Community on Twitter: https://www.twitter.com/FlutterComm

--

--