Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin: adding Cognito Flutter mobile app #6256

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions kotlin/usecases/cognito_flutter_mobile_app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/

# Symbolication related
app.*.symbols

# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
193 changes: 193 additions & 0 deletions kotlin/usecases/cognito_flutter_mobile_app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Sample Flutter App for Integrating with AWS Cognito and implementing Authentication Functionality.

## Prerequisite
- Install Android Studio or the Android Command-Line Tools from [https://developer.android.com/](https://developer.android.com/studio/install).
- Install Flutter from [https://docs.flutter.dev/get-started](https://docs.flutter.dev/get-started/install/macos/mobile-android?tab=download).
- Optionally install IDE with Flutter Plugin for [Visual Studio Code](https://docs.flutter.dev/tools/vs-code), [Android Studio](https://docs.flutter.dev/tools/android-studio) or [IntelliJ IDEA](https://plugins.jetbrains.com/plugin/9212-flutter).
- Accept Licences using `flutter doctor --android-licenses`.
- Verify Flutter Installation using `flutter doctor -v`.
- Add Android emulator using `flutter emulators --create --name android-device`.
- Launch Android emulator using `flutter emulators --launch android-device`

## Step-1: Set Up AWS Cognito User Pool and App Client ID
- Log in to the AWS Management Console.
- Navigate to Amazon Cognito and select "Manage User Pools."
- Click "Create a user pool," name it, and follow the prompts to configure settings.
- Set up an App Client if you haven't already.
- Make sure to note your Pool ID and App Client ID (without a client secret).

## Step 2: Add Dependencies
- Add dependency for AWS cognito by executing `flutter pub add amazon_cognito_identity_dart_2` in your flutter project.
- Add dependency for Secure storage by executing `flutter pub add flutter_secure_storage` in your flutter project.
- Verify these dependencies to your package's `pubspec.yaml`.

## Step 3: Initialize Cognito
Update `assets/config.json` and initialize your Cognito user pool with your Pool ID and App Client ID:
```
{
"UserPoolID": "<<YOUR USER POOL ID>>",
"ClientID": "<< YOUR CLIENT ID>>"
}
```

## Step 4: Integrate with AWS Cognito APIs
See `cognito_manager.dart` for an example of integrating with AWS Cognito, e.g.,,

```
import 'package:amazon_cognito_identity_dart_2/cognito.dart';
import 'config.dart';

class CognitoServiceException implements Exception {
final String message;
CognitoServiceException(this.message);
}

class User {
String username;
bool userConfirmed;
bool sessionValid;
String? userSub;
Map<String, dynamic> claims;

User(this.username, this.userConfirmed, this.sessionValid, this.userSub,
this.claims);
}

class CognitoManager {
late final CognitoUserPool userPool;

CognitoManager();

Future<void> init() async {
final config = await loadConfig();
userPool = CognitoUserPool(config.userPoolID, config.clientID);
}

Future<User> signUp(String email, String password) async {
final userAttributes = [
AttributeArg(name: 'email', value: email),
// Add other attributes as needed
];

try {
final result = await userPool.signUp(email, password,
userAttributes: userAttributes);
return User(
email, result.userConfirmed ?? false, false, result.userSub, {});
} catch (e) {
throw CognitoServiceException(e.toString());
}
}

Future<bool> confirmUser(String email, String confirmationCode) async {
final cognitoUser = CognitoUser(email, userPool);
try {
return await cognitoUser.confirmRegistration(confirmationCode);
} catch (e) {
throw CognitoServiceException(e.toString());
}
}

Future<User> signIn(String email, String password) async {
final cognitoUser = CognitoUser(email, userPool);
final authDetails =
AuthenticationDetails(username: email, password: password);

try {
final session = await cognitoUser.authenticateUser(authDetails);
if (session == null) {
throw CognitoClientException("session not found");
}
var claims = <String, dynamic>{};
claims.addAll(session.idToken.payload);
claims.addAll(session.accessToken.payload);
return User(email, true, session.isValid(),
session.idToken.getSub() ?? "", claims);
} catch (e) {
throw CognitoServiceException(e.toString());
}
}
}
```

## Step 4: Implementing UI
See `main.dart` for a sample UI to implement sign up or sign in functionality, e.g.,
```
import 'package:flutter/material.dart';
import 'cognito_manager.dart';

...

class SignUpView extends StatefulWidget {
@override
_SignUpViewState createState() => _SignUpViewState();
}

class _SignUpViewState extends State<SignUpView> {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
late final CognitoManager _cognitoManager;

@override
void initState() {
super.initState();
_cognitoManager = CognitoManager();
_initCognitoManager();
}

Future<void> _initCognitoManager() async {
await _cognitoManager.init();
}

void _signUp() async {
final email = _emailController.text;
final password = _passwordController.text;

try {
await _cognitoManager.signUp(email, password);
DefaultTabController.of(context).animateTo(1);
} on CognitoServiceException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(e.message)),
);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sign Up')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
),
TextField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
ElevatedButton(
onPressed: _signUp,
child: const Text('Sign Up'),
),
],
),
),
);
}
}

...
```
## Step 5: Run Application
Launch the application using `flutter run`.

## Resources
- [AWS Cognito](https://aws.amazon.com/cognito/)
- [Flutter Getting Started](https://docs.flutter.dev/get-started/codelab)
- [Flutter Cookbook](https://docs.flutter.dev/cookbook)
- [Flutter Documentation](https://docs.flutter.dev/)
28 changes: 28 additions & 0 deletions kotlin/usecases/cognito_flutter_mobile_app/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
13 changes: 13 additions & 0 deletions kotlin/usecases/cognito_flutter_mobile_app/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}

android {
namespace "com.example.android_app"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.android_app"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}

flutter {
source '../..'
}

dependencies {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="android-app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
Loading
Loading